Merge with docker/libnetwork
Signed-off-by: Jana Radhakrishnan <mrjana@socketplane.io>
This commit is contained in:
commit
91589f4948
137 changed files with 13258 additions and 120 deletions
38
libnetwork/Godeps/Godeps.json
generated
Normal file
38
libnetwork/Godeps/Godeps.json
generated
Normal file
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
"ImportPath": "github.com/docker/libnetwork",
|
||||
"GoVersion": "go1.4.2",
|
||||
"Packages": [
|
||||
"./..."
|
||||
],
|
||||
"Deps": [
|
||||
{
|
||||
"ImportPath": "github.com/Sirupsen/logrus",
|
||||
"Comment": "v0.6.4-12-g467d9d5",
|
||||
"Rev": "467d9d55c2d2c17248441a8fc661561161f40d5e"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/daemon/networkdriver",
|
||||
"Comment": "v1.4.1-1379-g8e107a9",
|
||||
"Rev": "8e107a93210c54f22ec1354d969c771b1abfbe05"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/pkg/parsers/kernel",
|
||||
"Comment": "v1.4.1-1379-g8e107a9",
|
||||
"Rev": "8e107a93210c54f22ec1354d969c771b1abfbe05"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/pkg/reexec",
|
||||
"Comment": "v1.4.1-1379-g8e107a9",
|
||||
"Rev": "8e107a93210c54f22ec1354d969c771b1abfbe05"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/libcontainer/netlink",
|
||||
"Comment": "v1.4.0-324-g88989e6",
|
||||
"Rev": "88989e66d3a1ab960deb37f3dd7f824d85e1b9bc"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/vishvananda/netlink",
|
||||
"Rev": "8eb64238879fed52fd51c5b30ad20b928fb4c36c"
|
||||
}
|
||||
]
|
||||
}
|
5
libnetwork/Godeps/Readme
generated
Normal file
5
libnetwork/Godeps/Readme
generated
Normal file
|
@ -0,0 +1,5 @@
|
|||
This directory tree is generated automatically by godep.
|
||||
|
||||
Please do not edit.
|
||||
|
||||
See https://github.com/tools/godep for more information.
|
2
libnetwork/Godeps/_workspace/.gitignore
generated
vendored
Normal file
2
libnetwork/Godeps/_workspace/.gitignore
generated
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
/pkg
|
||||
/bin
|
1
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/.gitignore
generated
vendored
Normal file
1
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/.gitignore
generated
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
logrus
|
8
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/.travis.yml
generated
vendored
Normal file
8
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/.travis.yml
generated
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
language: go
|
||||
go:
|
||||
- 1.2
|
||||
- 1.3
|
||||
- 1.4
|
||||
- tip
|
||||
install:
|
||||
- go get -t ./...
|
21
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/LICENSE
generated
vendored
Normal file
21
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Simon Eskildsen
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
373
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/README.md
generated
vendored
Normal file
373
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/README.md
generated
vendored
Normal file
|
@ -0,0 +1,373 @@
|
|||
# Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:"/> [](https://travis-ci.org/Sirupsen/logrus) [][godoc]
|
||||
|
||||
Logrus is a structured logger for Go (golang), completely API compatible with
|
||||
the standard library logger. [Godoc][godoc]. **Please note the Logrus API is not
|
||||
yet stable (pre 1.0), the core API is unlikely to change much but please version
|
||||
control your Logrus to make sure you aren't fetching latest `master` on every
|
||||
build.**
|
||||
|
||||
Nicely color-coded in development (when a TTY is attached, otherwise just
|
||||
plain text):
|
||||
|
||||

|
||||
|
||||
With `log.Formatter = new(logrus.JSONFormatter)`, for easy parsing by logstash
|
||||
or Splunk:
|
||||
|
||||
```json
|
||||
{"animal":"walrus","level":"info","msg":"A group of walrus emerges from the
|
||||
ocean","size":10,"time":"2014-03-10 19:57:38.562264131 -0400 EDT"}
|
||||
|
||||
{"level":"warning","msg":"The group's number increased tremendously!",
|
||||
"number":122,"omg":true,"time":"2014-03-10 19:57:38.562471297 -0400 EDT"}
|
||||
|
||||
{"animal":"walrus","level":"info","msg":"A giant walrus appears!",
|
||||
"size":10,"time":"2014-03-10 19:57:38.562500591 -0400 EDT"}
|
||||
|
||||
{"animal":"walrus","level":"info","msg":"Tremendously sized cow enters the ocean.",
|
||||
"size":9,"time":"2014-03-10 19:57:38.562527896 -0400 EDT"}
|
||||
|
||||
{"level":"fatal","msg":"The ice breaks!","number":100,"omg":true,
|
||||
"time":"2014-03-10 19:57:38.562543128 -0400 EDT"}
|
||||
```
|
||||
|
||||
With the default `log.Formatter = new(logrus.TextFormatter)` when a TTY is not
|
||||
attached, the output is compatible with the
|
||||
[logfmt](http://godoc.org/github.com/kr/logfmt) format:
|
||||
|
||||
```text
|
||||
time="2014-04-20 15:36:23.830442383 -0400 EDT" level="info" msg="A group of walrus emerges from the ocean" animal="walrus" size=10
|
||||
time="2014-04-20 15:36:23.830584199 -0400 EDT" level="warning" msg="The group's number increased tremendously!" omg=true number=122
|
||||
time="2014-04-20 15:36:23.830596521 -0400 EDT" level="info" msg="A giant walrus appears!" animal="walrus" size=10
|
||||
time="2014-04-20 15:36:23.830611837 -0400 EDT" level="info" msg="Tremendously sized cow enters the ocean." animal="walrus" size=9
|
||||
time="2014-04-20 15:36:23.830626464 -0400 EDT" level="fatal" msg="The ice breaks!" omg=true number=100
|
||||
```
|
||||
|
||||
#### Example
|
||||
|
||||
The simplest way to use Logrus is simply the package-level exported logger:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
log "github.com/Sirupsen/logrus"
|
||||
)
|
||||
|
||||
func main() {
|
||||
log.WithFields(log.Fields{
|
||||
"animal": "walrus",
|
||||
}).Info("A walrus appears")
|
||||
}
|
||||
```
|
||||
|
||||
Note that it's completely api-compatible with the stdlib logger, so you can
|
||||
replace your `log` imports everywhere with `log "github.com/Sirupsen/logrus"`
|
||||
and you'll now have the flexibility of Logrus. You can customize it all you
|
||||
want:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/Sirupsen/logrus/hooks/airbrake"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Log as JSON instead of the default ASCII formatter.
|
||||
log.SetFormatter(&log.JSONFormatter{})
|
||||
|
||||
// Use the Airbrake hook to report errors that have Error severity or above to
|
||||
// an exception tracker. You can create custom hooks, see the Hooks section.
|
||||
log.AddHook(&logrus_airbrake.AirbrakeHook{})
|
||||
|
||||
// Output to stderr instead of stdout, could also be a file.
|
||||
log.SetOutput(os.Stderr)
|
||||
|
||||
// Only log the warning severity or above.
|
||||
log.SetLevel(log.WarnLevel)
|
||||
}
|
||||
|
||||
func main() {
|
||||
log.WithFields(log.Fields{
|
||||
"animal": "walrus",
|
||||
"size": 10,
|
||||
}).Info("A group of walrus emerges from the ocean")
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
"omg": true,
|
||||
"number": 122,
|
||||
}).Warn("The group's number increased tremendously!")
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
"omg": true,
|
||||
"number": 100,
|
||||
}).Fatal("The ice breaks!")
|
||||
}
|
||||
```
|
||||
|
||||
For more advanced usage such as logging to multiple locations from the same
|
||||
application, you can also create an instance of the `logrus` Logger:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/Sirupsen/logrus"
|
||||
)
|
||||
|
||||
// Create a new instance of the logger. You can have any number of instances.
|
||||
var log = logrus.New()
|
||||
|
||||
func main() {
|
||||
// The API for setting attributes is a little different than the package level
|
||||
// exported logger. See Godoc.
|
||||
log.Out = os.Stderr
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"animal": "walrus",
|
||||
"size": 10,
|
||||
}).Info("A group of walrus emerges from the ocean")
|
||||
}
|
||||
```
|
||||
|
||||
#### Fields
|
||||
|
||||
Logrus encourages careful, structured logging though logging fields instead of
|
||||
long, unparseable error messages. For example, instead of: `log.Fatalf("Failed
|
||||
to send event %s to topic %s with key %d")`, you should log the much more
|
||||
discoverable:
|
||||
|
||||
```go
|
||||
log.WithFields(log.Fields{
|
||||
"event": event,
|
||||
"topic": topic,
|
||||
"key": key,
|
||||
}).Fatal("Failed to send event")
|
||||
```
|
||||
|
||||
We've found this API forces you to think about logging in a way that produces
|
||||
much more useful logging messages. We've been in countless situations where just
|
||||
a single added field to a log statement that was already there would've saved us
|
||||
hours. The `WithFields` call is optional.
|
||||
|
||||
In general, with Logrus using any of the `printf`-family functions should be
|
||||
seen as a hint you should add a field, however, you can still use the
|
||||
`printf`-family functions with Logrus.
|
||||
|
||||
#### Hooks
|
||||
|
||||
You can add hooks for logging levels. For example to send errors to an exception
|
||||
tracking service on `Error`, `Fatal` and `Panic`, info to StatsD or log to
|
||||
multiple places simultaneously, e.g. syslog.
|
||||
|
||||
```go
|
||||
// Not the real implementation of the Airbrake hook. Just a simple sample.
|
||||
import (
|
||||
log "github.com/Sirupsen/logrus"
|
||||
)
|
||||
|
||||
func init() {
|
||||
log.AddHook(new(AirbrakeHook))
|
||||
}
|
||||
|
||||
type AirbrakeHook struct{}
|
||||
|
||||
// `Fire()` takes the entry that the hook is fired for. `entry.Data[]` contains
|
||||
// the fields for the entry. See the Fields section of the README.
|
||||
func (hook *AirbrakeHook) Fire(entry *logrus.Entry) error {
|
||||
err := airbrake.Notify(entry.Data["error"].(error))
|
||||
if err != nil {
|
||||
log.WithFields(log.Fields{
|
||||
"source": "airbrake",
|
||||
"endpoint": airbrake.Endpoint,
|
||||
}).Info("Failed to send error to Airbrake")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// `Levels()` returns a slice of `Levels` the hook is fired for.
|
||||
func (hook *AirbrakeHook) Levels() []log.Level {
|
||||
return []log.Level{
|
||||
log.ErrorLevel,
|
||||
log.FatalLevel,
|
||||
log.PanicLevel,
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Logrus comes with built-in hooks. Add those, or your custom hook, in `init`:
|
||||
|
||||
```go
|
||||
import (
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/Sirupsen/logrus/hooks/airbrake"
|
||||
"github.com/Sirupsen/logrus/hooks/syslog"
|
||||
"log/syslog"
|
||||
)
|
||||
|
||||
func init() {
|
||||
log.AddHook(new(logrus_airbrake.AirbrakeHook))
|
||||
|
||||
hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "")
|
||||
if err != nil {
|
||||
log.Error("Unable to connect to local syslog daemon")
|
||||
} else {
|
||||
log.AddHook(hook)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
* [`github.com/Sirupsen/logrus/hooks/airbrake`](https://github.com/Sirupsen/logrus/blob/master/hooks/airbrake/airbrake.go)
|
||||
Send errors to an exception tracking service compatible with the Airbrake API.
|
||||
Uses [`airbrake-go`](https://github.com/tobi/airbrake-go) behind the scenes.
|
||||
|
||||
* [`github.com/Sirupsen/logrus/hooks/papertrail`](https://github.com/Sirupsen/logrus/blob/master/hooks/papertrail/papertrail.go)
|
||||
Send errors to the Papertrail hosted logging service via UDP.
|
||||
|
||||
* [`github.com/Sirupsen/logrus/hooks/syslog`](https://github.com/Sirupsen/logrus/blob/master/hooks/syslog/syslog.go)
|
||||
Send errors to remote syslog server.
|
||||
Uses standard library `log/syslog` behind the scenes.
|
||||
|
||||
* [`github.com/nubo/hiprus`](https://github.com/nubo/hiprus)
|
||||
Send errors to a channel in hipchat.
|
||||
|
||||
* [`github.com/sebest/logrusly`](https://github.com/sebest/logrusly)
|
||||
Send logs to Loggly (https://www.loggly.com/)
|
||||
|
||||
* [`github.com/johntdyer/slackrus`](https://github.com/johntdyer/slackrus)
|
||||
Hook for Slack chat.
|
||||
|
||||
#### Level logging
|
||||
|
||||
Logrus has six logging levels: Debug, Info, Warning, Error, Fatal and Panic.
|
||||
|
||||
```go
|
||||
log.Debug("Useful debugging information.")
|
||||
log.Info("Something noteworthy happened!")
|
||||
log.Warn("You should probably take a look at this.")
|
||||
log.Error("Something failed but I'm not quitting.")
|
||||
// Calls os.Exit(1) after logging
|
||||
log.Fatal("Bye.")
|
||||
// Calls panic() after logging
|
||||
log.Panic("I'm bailing.")
|
||||
```
|
||||
|
||||
You can set the logging level on a `Logger`, then it will only log entries with
|
||||
that severity or anything above it:
|
||||
|
||||
```go
|
||||
// Will log anything that is info or above (warn, error, fatal, panic). Default.
|
||||
log.SetLevel(log.InfoLevel)
|
||||
```
|
||||
|
||||
It may be useful to set `log.Level = logrus.DebugLevel` in a debug or verbose
|
||||
environment if your application has that.
|
||||
|
||||
#### Entries
|
||||
|
||||
Besides the fields added with `WithField` or `WithFields` some fields are
|
||||
automatically added to all logging events:
|
||||
|
||||
1. `time`. The timestamp when the entry was created.
|
||||
2. `msg`. The logging message passed to `{Info,Warn,Error,Fatal,Panic}` after
|
||||
the `AddFields` call. E.g. `Failed to send event.`
|
||||
3. `level`. The logging level. E.g. `info`.
|
||||
|
||||
#### Environments
|
||||
|
||||
Logrus has no notion of environment.
|
||||
|
||||
If you wish for hooks and formatters to only be used in specific environments,
|
||||
you should handle that yourself. For example, if your application has a global
|
||||
variable `Environment`, which is a string representation of the environment you
|
||||
could do:
|
||||
|
||||
```go
|
||||
import (
|
||||
log "github.com/Sirupsen/logrus"
|
||||
)
|
||||
|
||||
init() {
|
||||
// do something here to set environment depending on an environment variable
|
||||
// or command-line flag
|
||||
if Environment == "production" {
|
||||
log.SetFormatter(logrus.JSONFormatter)
|
||||
} else {
|
||||
// The TextFormatter is default, you don't actually have to do this.
|
||||
log.SetFormatter(logrus.TextFormatter)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This configuration is how `logrus` was intended to be used, but JSON in
|
||||
production is mostly only useful if you do log aggregation with tools like
|
||||
Splunk or Logstash.
|
||||
|
||||
#### Formatters
|
||||
|
||||
The built-in logging formatters are:
|
||||
|
||||
* `logrus.TextFormatter`. Logs the event in colors if stdout is a tty, otherwise
|
||||
without colors.
|
||||
* *Note:* to force colored output when there is no TTY, set the `ForceColors`
|
||||
field to `true`. To force no colored output even if there is a TTY set the
|
||||
`DisableColors` field to `true`
|
||||
* `logrus.JSONFormatter`. Logs fields as JSON.
|
||||
|
||||
Third party logging formatters:
|
||||
|
||||
* [`zalgo`](https://github.com/aybabtme/logzalgo): invoking the P͉̫o̳̼̊w̖͈̰͎e̬͔̭͂r͚̼̹̲ ̫͓͉̳͈ō̠͕͖̚f̝͍̠ ͕̲̞͖͑Z̖̫̤̫ͪa͉̬͈̗l͖͎g̳̥o̰̥̅!̣͔̲̻͊̄ ̙̘̦̹̦.
|
||||
|
||||
You can define your formatter by implementing the `Formatter` interface,
|
||||
requiring a `Format` method. `Format` takes an `*Entry`. `entry.Data` is a
|
||||
`Fields` type (`map[string]interface{}`) with all your fields as well as the
|
||||
default ones (see Entries section above):
|
||||
|
||||
```go
|
||||
type MyJSONFormatter struct {
|
||||
}
|
||||
|
||||
log.SetFormatter(new(MyJSONFormatter))
|
||||
|
||||
func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
|
||||
// Note this doesn't include Time, Level and Message which are available on
|
||||
// the Entry. Consult `godoc` on information about those fields or read the
|
||||
// source of the official loggers.
|
||||
serialized, err := json.Marshal(entry.Data)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
|
||||
}
|
||||
return append(serialized, '\n'), nil
|
||||
}
|
||||
```
|
||||
|
||||
#### Logger as an `io.Writer`
|
||||
|
||||
Logrus can be transormed into an `io.Writer`. That writer is the end of an `io.Pipe` and it is your responsability to close it.
|
||||
|
||||
```go
|
||||
w := logger.Writer()
|
||||
defer w.Close()
|
||||
|
||||
srv := http.Server{
|
||||
// create a stdlib log.Logger that writes to
|
||||
// logrus.Logger.
|
||||
ErrorLog: log.New(w, "", 0),
|
||||
}
|
||||
```
|
||||
|
||||
Each line written to that writer will be printed the usual way, using formatters
|
||||
and hooks. The level for those entries is `info`.
|
||||
|
||||
#### Rotation
|
||||
|
||||
Log rotation is not provided with Logrus. Log rotation should be done by an
|
||||
external program (like `logrotated(8)`) that can compress and delete old log
|
||||
entries. It should not be a feature of the application-level logger.
|
||||
|
||||
|
||||
[godoc]: https://godoc.org/github.com/Sirupsen/logrus
|
252
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/entry.go
generated
vendored
Normal file
252
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/entry.go
generated
vendored
Normal file
|
@ -0,0 +1,252 @@
|
|||
package logrus
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
// An entry is the final or intermediate Logrus logging entry. It contains all
|
||||
// the fields passed with WithField{,s}. It's finally logged when Debug, Info,
|
||||
// Warn, Error, Fatal or Panic is called on it. These objects can be reused and
|
||||
// passed around as much as you wish to avoid field duplication.
|
||||
type Entry struct {
|
||||
Logger *Logger
|
||||
|
||||
// Contains all the fields set by the user.
|
||||
Data Fields
|
||||
|
||||
// Time at which the log entry was created
|
||||
Time time.Time
|
||||
|
||||
// Level the log entry was logged at: Debug, Info, Warn, Error, Fatal or Panic
|
||||
Level Level
|
||||
|
||||
// Message passed to Debug, Info, Warn, Error, Fatal or Panic
|
||||
Message string
|
||||
}
|
||||
|
||||
func NewEntry(logger *Logger) *Entry {
|
||||
return &Entry{
|
||||
Logger: logger,
|
||||
// Default is three fields, give a little extra room
|
||||
Data: make(Fields, 5),
|
||||
}
|
||||
}
|
||||
|
||||
// Returns a reader for the entry, which is a proxy to the formatter.
|
||||
func (entry *Entry) Reader() (*bytes.Buffer, error) {
|
||||
serialized, err := entry.Logger.Formatter.Format(entry)
|
||||
return bytes.NewBuffer(serialized), err
|
||||
}
|
||||
|
||||
// Returns the string representation from the reader and ultimately the
|
||||
// formatter.
|
||||
func (entry *Entry) String() (string, error) {
|
||||
reader, err := entry.Reader()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return reader.String(), err
|
||||
}
|
||||
|
||||
// Add a single field to the Entry.
|
||||
func (entry *Entry) WithField(key string, value interface{}) *Entry {
|
||||
return entry.WithFields(Fields{key: value})
|
||||
}
|
||||
|
||||
// Add a map of fields to the Entry.
|
||||
func (entry *Entry) WithFields(fields Fields) *Entry {
|
||||
data := Fields{}
|
||||
for k, v := range entry.Data {
|
||||
data[k] = v
|
||||
}
|
||||
for k, v := range fields {
|
||||
data[k] = v
|
||||
}
|
||||
return &Entry{Logger: entry.Logger, Data: data}
|
||||
}
|
||||
|
||||
func (entry *Entry) log(level Level, msg string) {
|
||||
entry.Time = time.Now()
|
||||
entry.Level = level
|
||||
entry.Message = msg
|
||||
|
||||
if err := entry.Logger.Hooks.Fire(level, entry); err != nil {
|
||||
entry.Logger.mu.Lock()
|
||||
fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err)
|
||||
entry.Logger.mu.Unlock()
|
||||
}
|
||||
|
||||
reader, err := entry.Reader()
|
||||
if err != nil {
|
||||
entry.Logger.mu.Lock()
|
||||
fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err)
|
||||
entry.Logger.mu.Unlock()
|
||||
}
|
||||
|
||||
entry.Logger.mu.Lock()
|
||||
defer entry.Logger.mu.Unlock()
|
||||
|
||||
_, err = io.Copy(entry.Logger.Out, reader)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err)
|
||||
}
|
||||
|
||||
// To avoid Entry#log() returning a value that only would make sense for
|
||||
// panic() to use in Entry#Panic(), we avoid the allocation by checking
|
||||
// directly here.
|
||||
if level <= PanicLevel {
|
||||
panic(entry)
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Debug(args ...interface{}) {
|
||||
if entry.Logger.Level >= DebugLevel {
|
||||
entry.log(DebugLevel, fmt.Sprint(args...))
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Print(args ...interface{}) {
|
||||
entry.Info(args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Info(args ...interface{}) {
|
||||
if entry.Logger.Level >= InfoLevel {
|
||||
entry.log(InfoLevel, fmt.Sprint(args...))
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Warn(args ...interface{}) {
|
||||
if entry.Logger.Level >= WarnLevel {
|
||||
entry.log(WarnLevel, fmt.Sprint(args...))
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Warning(args ...interface{}) {
|
||||
entry.Warn(args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Error(args ...interface{}) {
|
||||
if entry.Logger.Level >= ErrorLevel {
|
||||
entry.log(ErrorLevel, fmt.Sprint(args...))
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Fatal(args ...interface{}) {
|
||||
if entry.Logger.Level >= FatalLevel {
|
||||
entry.log(FatalLevel, fmt.Sprint(args...))
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func (entry *Entry) Panic(args ...interface{}) {
|
||||
if entry.Logger.Level >= PanicLevel {
|
||||
entry.log(PanicLevel, fmt.Sprint(args...))
|
||||
}
|
||||
panic(fmt.Sprint(args...))
|
||||
}
|
||||
|
||||
// Entry Printf family functions
|
||||
|
||||
func (entry *Entry) Debugf(format string, args ...interface{}) {
|
||||
if entry.Logger.Level >= DebugLevel {
|
||||
entry.Debug(fmt.Sprintf(format, args...))
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Infof(format string, args ...interface{}) {
|
||||
if entry.Logger.Level >= InfoLevel {
|
||||
entry.Info(fmt.Sprintf(format, args...))
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Printf(format string, args ...interface{}) {
|
||||
entry.Infof(format, args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Warnf(format string, args ...interface{}) {
|
||||
if entry.Logger.Level >= WarnLevel {
|
||||
entry.Warn(fmt.Sprintf(format, args...))
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Warningf(format string, args ...interface{}) {
|
||||
entry.Warnf(format, args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Errorf(format string, args ...interface{}) {
|
||||
if entry.Logger.Level >= ErrorLevel {
|
||||
entry.Error(fmt.Sprintf(format, args...))
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Fatalf(format string, args ...interface{}) {
|
||||
if entry.Logger.Level >= FatalLevel {
|
||||
entry.Fatal(fmt.Sprintf(format, args...))
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Panicf(format string, args ...interface{}) {
|
||||
if entry.Logger.Level >= PanicLevel {
|
||||
entry.Panic(fmt.Sprintf(format, args...))
|
||||
}
|
||||
}
|
||||
|
||||
// Entry Println family functions
|
||||
|
||||
func (entry *Entry) Debugln(args ...interface{}) {
|
||||
if entry.Logger.Level >= DebugLevel {
|
||||
entry.Debug(entry.sprintlnn(args...))
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Infoln(args ...interface{}) {
|
||||
if entry.Logger.Level >= InfoLevel {
|
||||
entry.Info(entry.sprintlnn(args...))
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Println(args ...interface{}) {
|
||||
entry.Infoln(args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Warnln(args ...interface{}) {
|
||||
if entry.Logger.Level >= WarnLevel {
|
||||
entry.Warn(entry.sprintlnn(args...))
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Warningln(args ...interface{}) {
|
||||
entry.Warnln(args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Errorln(args ...interface{}) {
|
||||
if entry.Logger.Level >= ErrorLevel {
|
||||
entry.Error(entry.sprintlnn(args...))
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Fatalln(args ...interface{}) {
|
||||
if entry.Logger.Level >= FatalLevel {
|
||||
entry.Fatal(entry.sprintlnn(args...))
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Panicln(args ...interface{}) {
|
||||
if entry.Logger.Level >= PanicLevel {
|
||||
entry.Panic(entry.sprintlnn(args...))
|
||||
}
|
||||
}
|
||||
|
||||
// Sprintlnn => Sprint no newline. This is to get the behavior of how
|
||||
// fmt.Sprintln where spaces are always added between operands, regardless of
|
||||
// their type. Instead of vendoring the Sprintln implementation to spare a
|
||||
// string allocation, we do the simplest thing.
|
||||
func (entry *Entry) sprintlnn(args ...interface{}) string {
|
||||
msg := fmt.Sprintln(args...)
|
||||
return msg[:len(msg)-1]
|
||||
}
|
53
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/entry_test.go
generated
vendored
Normal file
53
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/entry_test.go
generated
vendored
Normal file
|
@ -0,0 +1,53 @@
|
|||
package logrus
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestEntryPanicln(t *testing.T) {
|
||||
errBoom := fmt.Errorf("boom time")
|
||||
|
||||
defer func() {
|
||||
p := recover()
|
||||
assert.NotNil(t, p)
|
||||
|
||||
switch pVal := p.(type) {
|
||||
case *Entry:
|
||||
assert.Equal(t, "kaboom", pVal.Message)
|
||||
assert.Equal(t, errBoom, pVal.Data["err"])
|
||||
default:
|
||||
t.Fatalf("want type *Entry, got %T: %#v", pVal, pVal)
|
||||
}
|
||||
}()
|
||||
|
||||
logger := New()
|
||||
logger.Out = &bytes.Buffer{}
|
||||
entry := NewEntry(logger)
|
||||
entry.WithField("err", errBoom).Panicln("kaboom")
|
||||
}
|
||||
|
||||
func TestEntryPanicf(t *testing.T) {
|
||||
errBoom := fmt.Errorf("boom again")
|
||||
|
||||
defer func() {
|
||||
p := recover()
|
||||
assert.NotNil(t, p)
|
||||
|
||||
switch pVal := p.(type) {
|
||||
case *Entry:
|
||||
assert.Equal(t, "kaboom true", pVal.Message)
|
||||
assert.Equal(t, errBoom, pVal.Data["err"])
|
||||
default:
|
||||
t.Fatalf("want type *Entry, got %T: %#v", pVal, pVal)
|
||||
}
|
||||
}()
|
||||
|
||||
logger := New()
|
||||
logger.Out = &bytes.Buffer{}
|
||||
entry := NewEntry(logger)
|
||||
entry.WithField("err", errBoom).Panicf("kaboom %v", true)
|
||||
}
|
40
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/examples/basic/basic.go
generated
vendored
Normal file
40
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/examples/basic/basic.go
generated
vendored
Normal file
|
@ -0,0 +1,40 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/Sirupsen/logrus"
|
||||
)
|
||||
|
||||
var log = logrus.New()
|
||||
|
||||
func init() {
|
||||
log.Formatter = new(logrus.JSONFormatter)
|
||||
log.Formatter = new(logrus.TextFormatter) // default
|
||||
}
|
||||
|
||||
func main() {
|
||||
defer func() {
|
||||
err := recover()
|
||||
if err != nil {
|
||||
log.WithFields(logrus.Fields{
|
||||
"omg": true,
|
||||
"err": err,
|
||||
"number": 100,
|
||||
}).Fatal("The ice breaks!")
|
||||
}
|
||||
}()
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"animal": "walrus",
|
||||
"size": 10,
|
||||
}).Info("A group of walrus emerges from the ocean")
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"omg": true,
|
||||
"number": 122,
|
||||
}).Warn("The group's number increased tremendously!")
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"animal": "orca",
|
||||
"size": 9009,
|
||||
}).Panic("It's over 9000!")
|
||||
}
|
35
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/examples/hook/hook.go
generated
vendored
Normal file
35
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/examples/hook/hook.go
generated
vendored
Normal file
|
@ -0,0 +1,35 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/Sirupsen/logrus/hooks/airbrake"
|
||||
"github.com/tobi/airbrake-go"
|
||||
)
|
||||
|
||||
var log = logrus.New()
|
||||
|
||||
func init() {
|
||||
log.Formatter = new(logrus.TextFormatter) // default
|
||||
log.Hooks.Add(new(logrus_airbrake.AirbrakeHook))
|
||||
}
|
||||
|
||||
func main() {
|
||||
airbrake.Endpoint = "https://exceptions.whatever.com/notifier_api/v2/notices.xml"
|
||||
airbrake.ApiKey = "whatever"
|
||||
airbrake.Environment = "production"
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"animal": "walrus",
|
||||
"size": 10,
|
||||
}).Info("A group of walrus emerges from the ocean")
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"omg": true,
|
||||
"number": 122,
|
||||
}).Warn("The group's number increased tremendously!")
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"omg": true,
|
||||
"number": 100,
|
||||
}).Fatal("The ice breaks!")
|
||||
}
|
186
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/exported.go
generated
vendored
Normal file
186
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/exported.go
generated
vendored
Normal file
|
@ -0,0 +1,186 @@
|
|||
package logrus
|
||||
|
||||
import (
|
||||
"io"
|
||||
)
|
||||
|
||||
var (
|
||||
// std is the name of the standard logger in stdlib `log`
|
||||
std = New()
|
||||
)
|
||||
|
||||
func StandardLogger() *Logger {
|
||||
return std
|
||||
}
|
||||
|
||||
// SetOutput sets the standard logger output.
|
||||
func SetOutput(out io.Writer) {
|
||||
std.mu.Lock()
|
||||
defer std.mu.Unlock()
|
||||
std.Out = out
|
||||
}
|
||||
|
||||
// SetFormatter sets the standard logger formatter.
|
||||
func SetFormatter(formatter Formatter) {
|
||||
std.mu.Lock()
|
||||
defer std.mu.Unlock()
|
||||
std.Formatter = formatter
|
||||
}
|
||||
|
||||
// SetLevel sets the standard logger level.
|
||||
func SetLevel(level Level) {
|
||||
std.mu.Lock()
|
||||
defer std.mu.Unlock()
|
||||
std.Level = level
|
||||
}
|
||||
|
||||
// GetLevel returns the standard logger level.
|
||||
func GetLevel() Level {
|
||||
return std.Level
|
||||
}
|
||||
|
||||
// AddHook adds a hook to the standard logger hooks.
|
||||
func AddHook(hook Hook) {
|
||||
std.mu.Lock()
|
||||
defer std.mu.Unlock()
|
||||
std.Hooks.Add(hook)
|
||||
}
|
||||
|
||||
// WithField creates an entry from the standard logger and adds a field to
|
||||
// it. If you want multiple fields, use `WithFields`.
|
||||
//
|
||||
// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal
|
||||
// or Panic on the Entry it returns.
|
||||
func WithField(key string, value interface{}) *Entry {
|
||||
return std.WithField(key, value)
|
||||
}
|
||||
|
||||
// WithFields creates an entry from the standard logger and adds multiple
|
||||
// fields to it. This is simply a helper for `WithField`, invoking it
|
||||
// once for each field.
|
||||
//
|
||||
// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal
|
||||
// or Panic on the Entry it returns.
|
||||
func WithFields(fields Fields) *Entry {
|
||||
return std.WithFields(fields)
|
||||
}
|
||||
|
||||
// Debug logs a message at level Debug on the standard logger.
|
||||
func Debug(args ...interface{}) {
|
||||
std.Debug(args...)
|
||||
}
|
||||
|
||||
// Print logs a message at level Info on the standard logger.
|
||||
func Print(args ...interface{}) {
|
||||
std.Print(args...)
|
||||
}
|
||||
|
||||
// Info logs a message at level Info on the standard logger.
|
||||
func Info(args ...interface{}) {
|
||||
std.Info(args...)
|
||||
}
|
||||
|
||||
// Warn logs a message at level Warn on the standard logger.
|
||||
func Warn(args ...interface{}) {
|
||||
std.Warn(args...)
|
||||
}
|
||||
|
||||
// Warning logs a message at level Warn on the standard logger.
|
||||
func Warning(args ...interface{}) {
|
||||
std.Warning(args...)
|
||||
}
|
||||
|
||||
// Error logs a message at level Error on the standard logger.
|
||||
func Error(args ...interface{}) {
|
||||
std.Error(args...)
|
||||
}
|
||||
|
||||
// Panic logs a message at level Panic on the standard logger.
|
||||
func Panic(args ...interface{}) {
|
||||
std.Panic(args...)
|
||||
}
|
||||
|
||||
// Fatal logs a message at level Fatal on the standard logger.
|
||||
func Fatal(args ...interface{}) {
|
||||
std.Fatal(args...)
|
||||
}
|
||||
|
||||
// Debugf logs a message at level Debug on the standard logger.
|
||||
func Debugf(format string, args ...interface{}) {
|
||||
std.Debugf(format, args...)
|
||||
}
|
||||
|
||||
// Printf logs a message at level Info on the standard logger.
|
||||
func Printf(format string, args ...interface{}) {
|
||||
std.Printf(format, args...)
|
||||
}
|
||||
|
||||
// Infof logs a message at level Info on the standard logger.
|
||||
func Infof(format string, args ...interface{}) {
|
||||
std.Infof(format, args...)
|
||||
}
|
||||
|
||||
// Warnf logs a message at level Warn on the standard logger.
|
||||
func Warnf(format string, args ...interface{}) {
|
||||
std.Warnf(format, args...)
|
||||
}
|
||||
|
||||
// Warningf logs a message at level Warn on the standard logger.
|
||||
func Warningf(format string, args ...interface{}) {
|
||||
std.Warningf(format, args...)
|
||||
}
|
||||
|
||||
// Errorf logs a message at level Error on the standard logger.
|
||||
func Errorf(format string, args ...interface{}) {
|
||||
std.Errorf(format, args...)
|
||||
}
|
||||
|
||||
// Panicf logs a message at level Panic on the standard logger.
|
||||
func Panicf(format string, args ...interface{}) {
|
||||
std.Panicf(format, args...)
|
||||
}
|
||||
|
||||
// Fatalf logs a message at level Fatal on the standard logger.
|
||||
func Fatalf(format string, args ...interface{}) {
|
||||
std.Fatalf(format, args...)
|
||||
}
|
||||
|
||||
// Debugln logs a message at level Debug on the standard logger.
|
||||
func Debugln(args ...interface{}) {
|
||||
std.Debugln(args...)
|
||||
}
|
||||
|
||||
// Println logs a message at level Info on the standard logger.
|
||||
func Println(args ...interface{}) {
|
||||
std.Println(args...)
|
||||
}
|
||||
|
||||
// Infoln logs a message at level Info on the standard logger.
|
||||
func Infoln(args ...interface{}) {
|
||||
std.Infoln(args...)
|
||||
}
|
||||
|
||||
// Warnln logs a message at level Warn on the standard logger.
|
||||
func Warnln(args ...interface{}) {
|
||||
std.Warnln(args...)
|
||||
}
|
||||
|
||||
// Warningln logs a message at level Warn on the standard logger.
|
||||
func Warningln(args ...interface{}) {
|
||||
std.Warningln(args...)
|
||||
}
|
||||
|
||||
// Errorln logs a message at level Error on the standard logger.
|
||||
func Errorln(args ...interface{}) {
|
||||
std.Errorln(args...)
|
||||
}
|
||||
|
||||
// Panicln logs a message at level Panic on the standard logger.
|
||||
func Panicln(args ...interface{}) {
|
||||
std.Panicln(args...)
|
||||
}
|
||||
|
||||
// Fatalln logs a message at level Fatal on the standard logger.
|
||||
func Fatalln(args ...interface{}) {
|
||||
std.Fatalln(args...)
|
||||
}
|
44
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/formatter.go
generated
vendored
Normal file
44
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/formatter.go
generated
vendored
Normal file
|
@ -0,0 +1,44 @@
|
|||
package logrus
|
||||
|
||||
// The Formatter interface is used to implement a custom Formatter. It takes an
|
||||
// `Entry`. It exposes all the fields, including the default ones:
|
||||
//
|
||||
// * `entry.Data["msg"]`. The message passed from Info, Warn, Error ..
|
||||
// * `entry.Data["time"]`. The timestamp.
|
||||
// * `entry.Data["level"]. The level the entry was logged at.
|
||||
//
|
||||
// Any additional fields added with `WithField` or `WithFields` are also in
|
||||
// `entry.Data`. Format is expected to return an array of bytes which are then
|
||||
// logged to `logger.Out`.
|
||||
type Formatter interface {
|
||||
Format(*Entry) ([]byte, error)
|
||||
}
|
||||
|
||||
// This is to not silently overwrite `time`, `msg` and `level` fields when
|
||||
// dumping it. If this code wasn't there doing:
|
||||
//
|
||||
// logrus.WithField("level", 1).Info("hello")
|
||||
//
|
||||
// Would just silently drop the user provided level. Instead with this code
|
||||
// it'll logged as:
|
||||
//
|
||||
// {"level": "info", "fields.level": 1, "msg": "hello", "time": "..."}
|
||||
//
|
||||
// It's not exported because it's still using Data in an opinionated way. It's to
|
||||
// avoid code duplication between the two default formatters.
|
||||
func prefixFieldClashes(data Fields) {
|
||||
_, ok := data["time"]
|
||||
if ok {
|
||||
data["fields.time"] = data["time"]
|
||||
}
|
||||
|
||||
_, ok = data["msg"]
|
||||
if ok {
|
||||
data["fields.msg"] = data["msg"]
|
||||
}
|
||||
|
||||
_, ok = data["level"]
|
||||
if ok {
|
||||
data["fields.level"] = data["level"]
|
||||
}
|
||||
}
|
88
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/formatter_bench_test.go
generated
vendored
Normal file
88
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/formatter_bench_test.go
generated
vendored
Normal file
|
@ -0,0 +1,88 @@
|
|||
package logrus
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// smallFields is a small size data set for benchmarking
|
||||
var smallFields = Fields{
|
||||
"foo": "bar",
|
||||
"baz": "qux",
|
||||
"one": "two",
|
||||
"three": "four",
|
||||
}
|
||||
|
||||
// largeFields is a large size data set for benchmarking
|
||||
var largeFields = Fields{
|
||||
"foo": "bar",
|
||||
"baz": "qux",
|
||||
"one": "two",
|
||||
"three": "four",
|
||||
"five": "six",
|
||||
"seven": "eight",
|
||||
"nine": "ten",
|
||||
"eleven": "twelve",
|
||||
"thirteen": "fourteen",
|
||||
"fifteen": "sixteen",
|
||||
"seventeen": "eighteen",
|
||||
"nineteen": "twenty",
|
||||
"a": "b",
|
||||
"c": "d",
|
||||
"e": "f",
|
||||
"g": "h",
|
||||
"i": "j",
|
||||
"k": "l",
|
||||
"m": "n",
|
||||
"o": "p",
|
||||
"q": "r",
|
||||
"s": "t",
|
||||
"u": "v",
|
||||
"w": "x",
|
||||
"y": "z",
|
||||
"this": "will",
|
||||
"make": "thirty",
|
||||
"entries": "yeah",
|
||||
}
|
||||
|
||||
func BenchmarkSmallTextFormatter(b *testing.B) {
|
||||
doBenchmark(b, &TextFormatter{DisableColors: true}, smallFields)
|
||||
}
|
||||
|
||||
func BenchmarkLargeTextFormatter(b *testing.B) {
|
||||
doBenchmark(b, &TextFormatter{DisableColors: true}, largeFields)
|
||||
}
|
||||
|
||||
func BenchmarkSmallColoredTextFormatter(b *testing.B) {
|
||||
doBenchmark(b, &TextFormatter{ForceColors: true}, smallFields)
|
||||
}
|
||||
|
||||
func BenchmarkLargeColoredTextFormatter(b *testing.B) {
|
||||
doBenchmark(b, &TextFormatter{ForceColors: true}, largeFields)
|
||||
}
|
||||
|
||||
func BenchmarkSmallJSONFormatter(b *testing.B) {
|
||||
doBenchmark(b, &JSONFormatter{}, smallFields)
|
||||
}
|
||||
|
||||
func BenchmarkLargeJSONFormatter(b *testing.B) {
|
||||
doBenchmark(b, &JSONFormatter{}, largeFields)
|
||||
}
|
||||
|
||||
func doBenchmark(b *testing.B, formatter Formatter, fields Fields) {
|
||||
entry := &Entry{
|
||||
Time: time.Time{},
|
||||
Level: InfoLevel,
|
||||
Message: "message",
|
||||
Data: fields,
|
||||
}
|
||||
var d []byte
|
||||
var err error
|
||||
for i := 0; i < b.N; i++ {
|
||||
d, err = formatter.Format(entry)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
b.SetBytes(int64(len(d)))
|
||||
}
|
||||
}
|
122
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/hook_test.go
generated
vendored
Normal file
122
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/hook_test.go
generated
vendored
Normal file
|
@ -0,0 +1,122 @@
|
|||
package logrus
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type TestHook struct {
|
||||
Fired bool
|
||||
}
|
||||
|
||||
func (hook *TestHook) Fire(entry *Entry) error {
|
||||
hook.Fired = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (hook *TestHook) Levels() []Level {
|
||||
return []Level{
|
||||
DebugLevel,
|
||||
InfoLevel,
|
||||
WarnLevel,
|
||||
ErrorLevel,
|
||||
FatalLevel,
|
||||
PanicLevel,
|
||||
}
|
||||
}
|
||||
|
||||
func TestHookFires(t *testing.T) {
|
||||
hook := new(TestHook)
|
||||
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.Hooks.Add(hook)
|
||||
assert.Equal(t, hook.Fired, false)
|
||||
|
||||
log.Print("test")
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, hook.Fired, true)
|
||||
})
|
||||
}
|
||||
|
||||
type ModifyHook struct {
|
||||
}
|
||||
|
||||
func (hook *ModifyHook) Fire(entry *Entry) error {
|
||||
entry.Data["wow"] = "whale"
|
||||
return nil
|
||||
}
|
||||
|
||||
func (hook *ModifyHook) Levels() []Level {
|
||||
return []Level{
|
||||
DebugLevel,
|
||||
InfoLevel,
|
||||
WarnLevel,
|
||||
ErrorLevel,
|
||||
FatalLevel,
|
||||
PanicLevel,
|
||||
}
|
||||
}
|
||||
|
||||
func TestHookCanModifyEntry(t *testing.T) {
|
||||
hook := new(ModifyHook)
|
||||
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.Hooks.Add(hook)
|
||||
log.WithField("wow", "elephant").Print("test")
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["wow"], "whale")
|
||||
})
|
||||
}
|
||||
|
||||
func TestCanFireMultipleHooks(t *testing.T) {
|
||||
hook1 := new(ModifyHook)
|
||||
hook2 := new(TestHook)
|
||||
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.Hooks.Add(hook1)
|
||||
log.Hooks.Add(hook2)
|
||||
|
||||
log.WithField("wow", "elephant").Print("test")
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["wow"], "whale")
|
||||
assert.Equal(t, hook2.Fired, true)
|
||||
})
|
||||
}
|
||||
|
||||
type ErrorHook struct {
|
||||
Fired bool
|
||||
}
|
||||
|
||||
func (hook *ErrorHook) Fire(entry *Entry) error {
|
||||
hook.Fired = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (hook *ErrorHook) Levels() []Level {
|
||||
return []Level{
|
||||
ErrorLevel,
|
||||
}
|
||||
}
|
||||
|
||||
func TestErrorHookShouldntFireOnInfo(t *testing.T) {
|
||||
hook := new(ErrorHook)
|
||||
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.Hooks.Add(hook)
|
||||
log.Info("test")
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, hook.Fired, false)
|
||||
})
|
||||
}
|
||||
|
||||
func TestErrorHookShouldFireOnError(t *testing.T) {
|
||||
hook := new(ErrorHook)
|
||||
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.Hooks.Add(hook)
|
||||
log.Error("test")
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, hook.Fired, true)
|
||||
})
|
||||
}
|
34
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks.go
generated
vendored
Normal file
34
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks.go
generated
vendored
Normal file
|
@ -0,0 +1,34 @@
|
|||
package logrus
|
||||
|
||||
// A hook to be fired when logging on the logging levels returned from
|
||||
// `Levels()` on your implementation of the interface. Note that this is not
|
||||
// fired in a goroutine or a channel with workers, you should handle such
|
||||
// functionality yourself if your call is non-blocking and you don't wish for
|
||||
// the logging calls for levels returned from `Levels()` to block.
|
||||
type Hook interface {
|
||||
Levels() []Level
|
||||
Fire(*Entry) error
|
||||
}
|
||||
|
||||
// Internal type for storing the hooks on a logger instance.
|
||||
type levelHooks map[Level][]Hook
|
||||
|
||||
// Add a hook to an instance of logger. This is called with
|
||||
// `log.Hooks.Add(new(MyHook))` where `MyHook` implements the `Hook` interface.
|
||||
func (hooks levelHooks) Add(hook Hook) {
|
||||
for _, level := range hook.Levels() {
|
||||
hooks[level] = append(hooks[level], hook)
|
||||
}
|
||||
}
|
||||
|
||||
// Fire all the hooks for the passed level. Used by `entry.log` to fire
|
||||
// appropriate hooks for a log entry.
|
||||
func (hooks levelHooks) Fire(level Level, entry *Entry) error {
|
||||
for _, hook := range hooks[level] {
|
||||
if err := hook.Fire(entry); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
54
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/airbrake/airbrake.go
generated
vendored
Normal file
54
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/airbrake/airbrake.go
generated
vendored
Normal file
|
@ -0,0 +1,54 @@
|
|||
package logrus_airbrake
|
||||
|
||||
import (
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/tobi/airbrake-go"
|
||||
)
|
||||
|
||||
// AirbrakeHook to send exceptions to an exception-tracking service compatible
|
||||
// with the Airbrake API. You must set:
|
||||
// * airbrake.Endpoint
|
||||
// * airbrake.ApiKey
|
||||
// * airbrake.Environment (only sends exceptions when set to "production")
|
||||
//
|
||||
// Before using this hook, to send an error. Entries that trigger an Error,
|
||||
// Fatal or Panic should now include an "error" field to send to Airbrake.
|
||||
type AirbrakeHook struct{}
|
||||
|
||||
func (hook *AirbrakeHook) Fire(entry *logrus.Entry) error {
|
||||
if entry.Data["error"] == nil {
|
||||
entry.Logger.WithFields(logrus.Fields{
|
||||
"source": "airbrake",
|
||||
"endpoint": airbrake.Endpoint,
|
||||
}).Warn("Exceptions sent to Airbrake must have an 'error' key with the error")
|
||||
return nil
|
||||
}
|
||||
|
||||
err, ok := entry.Data["error"].(error)
|
||||
if !ok {
|
||||
entry.Logger.WithFields(logrus.Fields{
|
||||
"source": "airbrake",
|
||||
"endpoint": airbrake.Endpoint,
|
||||
}).Warn("Exceptions sent to Airbrake must have an `error` key of type `error`")
|
||||
return nil
|
||||
}
|
||||
|
||||
airErr := airbrake.Notify(err)
|
||||
if airErr != nil {
|
||||
entry.Logger.WithFields(logrus.Fields{
|
||||
"source": "airbrake",
|
||||
"endpoint": airbrake.Endpoint,
|
||||
"error": airErr,
|
||||
}).Warn("Failed to send error to Airbrake")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (hook *AirbrakeHook) Levels() []logrus.Level {
|
||||
return []logrus.Level{
|
||||
logrus.ErrorLevel,
|
||||
logrus.FatalLevel,
|
||||
logrus.PanicLevel,
|
||||
}
|
||||
}
|
28
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/papertrail/README.md
generated
vendored
Normal file
28
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/papertrail/README.md
generated
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
# Papertrail Hook for Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:" />
|
||||
|
||||
[Papertrail](https://papertrailapp.com) provides hosted log management. Once stored in Papertrail, you can [group](http://help.papertrailapp.com/kb/how-it-works/groups/) your logs on various dimensions, [search](http://help.papertrailapp.com/kb/how-it-works/search-syntax) them, and trigger [alerts](http://help.papertrailapp.com/kb/how-it-works/alerts).
|
||||
|
||||
In most deployments, you'll want to send logs to Papertrail via their [remote_syslog](http://help.papertrailapp.com/kb/configuration/configuring-centralized-logging-from-text-log-files-in-unix/) daemon, which requires no application-specific configuration. This hook is intended for relatively low-volume logging, likely in managed cloud hosting deployments where installing `remote_syslog` is not possible.
|
||||
|
||||
## Usage
|
||||
|
||||
You can find your Papertrail UDP port on your [Papertrail account page](https://papertrailapp.com/account/destinations). Substitute it below for `YOUR_PAPERTRAIL_UDP_PORT`.
|
||||
|
||||
For `YOUR_APP_NAME`, substitute a short string that will readily identify your application or service in the logs.
|
||||
|
||||
```go
|
||||
import (
|
||||
"log/syslog"
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/Sirupsen/logrus/hooks/papertrail"
|
||||
)
|
||||
|
||||
func main() {
|
||||
log := logrus.New()
|
||||
hook, err := logrus_papertrail.NewPapertrailHook("logs.papertrailapp.com", YOUR_PAPERTRAIL_UDP_PORT, YOUR_APP_NAME)
|
||||
|
||||
if err == nil {
|
||||
log.Hooks.Add(hook)
|
||||
}
|
||||
}
|
||||
```
|
55
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/papertrail/papertrail.go
generated
vendored
Normal file
55
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/papertrail/papertrail.go
generated
vendored
Normal file
|
@ -0,0 +1,55 @@
|
|||
package logrus_papertrail
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
)
|
||||
|
||||
const (
|
||||
format = "Jan 2 15:04:05"
|
||||
)
|
||||
|
||||
// PapertrailHook to send logs to a logging service compatible with the Papertrail API.
|
||||
type PapertrailHook struct {
|
||||
Host string
|
||||
Port int
|
||||
AppName string
|
||||
UDPConn net.Conn
|
||||
}
|
||||
|
||||
// NewPapertrailHook creates a hook to be added to an instance of logger.
|
||||
func NewPapertrailHook(host string, port int, appName string) (*PapertrailHook, error) {
|
||||
conn, err := net.Dial("udp", fmt.Sprintf("%s:%d", host, port))
|
||||
return &PapertrailHook{host, port, appName, conn}, err
|
||||
}
|
||||
|
||||
// Fire is called when a log event is fired.
|
||||
func (hook *PapertrailHook) Fire(entry *logrus.Entry) error {
|
||||
date := time.Now().Format(format)
|
||||
msg, _ := entry.String()
|
||||
payload := fmt.Sprintf("<22> %s %s: %s", date, hook.AppName, msg)
|
||||
|
||||
bytesWritten, err := hook.UDPConn.Write([]byte(payload))
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Unable to send log line to Papertrail via UDP. Wrote %d bytes before error: %v", bytesWritten, err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Levels returns the available logging levels.
|
||||
func (hook *PapertrailHook) Levels() []logrus.Level {
|
||||
return []logrus.Level{
|
||||
logrus.PanicLevel,
|
||||
logrus.FatalLevel,
|
||||
logrus.ErrorLevel,
|
||||
logrus.WarnLevel,
|
||||
logrus.InfoLevel,
|
||||
logrus.DebugLevel,
|
||||
}
|
||||
}
|
26
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/papertrail/papertrail_test.go
generated
vendored
Normal file
26
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/papertrail/papertrail_test.go
generated
vendored
Normal file
|
@ -0,0 +1,26 @@
|
|||
package logrus_papertrail
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/stvp/go-udp-testing"
|
||||
)
|
||||
|
||||
func TestWritingToUDP(t *testing.T) {
|
||||
port := 16661
|
||||
udp.SetAddr(fmt.Sprintf(":%d", port))
|
||||
|
||||
hook, err := NewPapertrailHook("localhost", port, "test")
|
||||
if err != nil {
|
||||
t.Errorf("Unable to connect to local UDP server.")
|
||||
}
|
||||
|
||||
log := logrus.New()
|
||||
log.Hooks.Add(hook)
|
||||
|
||||
udp.ShouldReceive(t, "foo", func() {
|
||||
log.Info("foo")
|
||||
})
|
||||
}
|
61
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/sentry/README.md
generated
vendored
Normal file
61
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/sentry/README.md
generated
vendored
Normal file
|
@ -0,0 +1,61 @@
|
|||
# Sentry Hook for Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:" />
|
||||
|
||||
[Sentry](https://getsentry.com) provides both self-hosted and hosted
|
||||
solutions for exception tracking.
|
||||
Both client and server are
|
||||
[open source](https://github.com/getsentry/sentry).
|
||||
|
||||
## Usage
|
||||
|
||||
Every sentry application defined on the server gets a different
|
||||
[DSN](https://www.getsentry.com/docs/). In the example below replace
|
||||
`YOUR_DSN` with the one created for your application.
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/Sirupsen/logrus/hooks/sentry"
|
||||
)
|
||||
|
||||
func main() {
|
||||
log := logrus.New()
|
||||
hook, err := logrus_sentry.NewSentryHook(YOUR_DSN, []logrus.Level{
|
||||
logrus.PanicLevel,
|
||||
logrus.FatalLevel,
|
||||
logrus.ErrorLevel,
|
||||
})
|
||||
|
||||
if err == nil {
|
||||
log.Hooks.Add(hook)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Special fields
|
||||
|
||||
Some logrus fields have a special meaning in this hook,
|
||||
these are server_name and logger.
|
||||
When logs are sent to sentry these fields are treated differently.
|
||||
- server_name (also known as hostname) is the name of the server which
|
||||
is logging the event (hostname.example.com)
|
||||
- logger is the part of the application which is logging the event.
|
||||
In go this usually means setting it to the name of the package.
|
||||
|
||||
## Timeout
|
||||
|
||||
`Timeout` is the time the sentry hook will wait for a response
|
||||
from the sentry server.
|
||||
|
||||
If this time elapses with no response from
|
||||
the server an error will be returned.
|
||||
|
||||
If `Timeout` is set to 0 the SentryHook will not wait for a reply
|
||||
and will assume a correct delivery.
|
||||
|
||||
The SentryHook has a default timeout of `100 milliseconds` when created
|
||||
with a call to `NewSentryHook`. This can be changed by assigning a value to the `Timeout` field:
|
||||
|
||||
```go
|
||||
hook, _ := logrus_sentry.NewSentryHook(...)
|
||||
hook.Timeout = 20*time.Seconds
|
||||
```
|
100
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/sentry/sentry.go
generated
vendored
Normal file
100
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/sentry/sentry.go
generated
vendored
Normal file
|
@ -0,0 +1,100 @@
|
|||
package logrus_sentry
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/getsentry/raven-go"
|
||||
)
|
||||
|
||||
var (
|
||||
severityMap = map[logrus.Level]raven.Severity{
|
||||
logrus.DebugLevel: raven.DEBUG,
|
||||
logrus.InfoLevel: raven.INFO,
|
||||
logrus.WarnLevel: raven.WARNING,
|
||||
logrus.ErrorLevel: raven.ERROR,
|
||||
logrus.FatalLevel: raven.FATAL,
|
||||
logrus.PanicLevel: raven.FATAL,
|
||||
}
|
||||
)
|
||||
|
||||
func getAndDel(d logrus.Fields, key string) (string, bool) {
|
||||
var (
|
||||
ok bool
|
||||
v interface{}
|
||||
val string
|
||||
)
|
||||
if v, ok = d[key]; !ok {
|
||||
return "", false
|
||||
}
|
||||
|
||||
if val, ok = v.(string); !ok {
|
||||
return "", false
|
||||
}
|
||||
delete(d, key)
|
||||
return val, true
|
||||
}
|
||||
|
||||
// SentryHook delivers logs to a sentry server.
|
||||
type SentryHook struct {
|
||||
// Timeout sets the time to wait for a delivery error from the sentry server.
|
||||
// If this is set to zero the server will not wait for any response and will
|
||||
// consider the message correctly sent
|
||||
Timeout time.Duration
|
||||
|
||||
client *raven.Client
|
||||
levels []logrus.Level
|
||||
}
|
||||
|
||||
// NewSentryHook creates a hook to be added to an instance of logger
|
||||
// and initializes the raven client.
|
||||
// This method sets the timeout to 100 milliseconds.
|
||||
func NewSentryHook(DSN string, levels []logrus.Level) (*SentryHook, error) {
|
||||
client, err := raven.NewClient(DSN, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &SentryHook{100 * time.Millisecond, client, levels}, nil
|
||||
}
|
||||
|
||||
// Called when an event should be sent to sentry
|
||||
// Special fields that sentry uses to give more information to the server
|
||||
// are extracted from entry.Data (if they are found)
|
||||
// These fields are: logger and server_name
|
||||
func (hook *SentryHook) Fire(entry *logrus.Entry) error {
|
||||
packet := &raven.Packet{
|
||||
Message: entry.Message,
|
||||
Timestamp: raven.Timestamp(entry.Time),
|
||||
Level: severityMap[entry.Level],
|
||||
Platform: "go",
|
||||
}
|
||||
|
||||
d := entry.Data
|
||||
|
||||
if logger, ok := getAndDel(d, "logger"); ok {
|
||||
packet.Logger = logger
|
||||
}
|
||||
if serverName, ok := getAndDel(d, "server_name"); ok {
|
||||
packet.ServerName = serverName
|
||||
}
|
||||
packet.Extra = map[string]interface{}(d)
|
||||
|
||||
_, errCh := hook.client.Capture(packet, nil)
|
||||
timeout := hook.Timeout
|
||||
if timeout != 0 {
|
||||
timeoutCh := time.After(timeout)
|
||||
select {
|
||||
case err := <-errCh:
|
||||
return err
|
||||
case <-timeoutCh:
|
||||
return fmt.Errorf("no response from sentry server in %s", timeout)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Levels returns the available logging levels.
|
||||
func (hook *SentryHook) Levels() []logrus.Level {
|
||||
return hook.levels
|
||||
}
|
97
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/sentry/sentry_test.go
generated
vendored
Normal file
97
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/sentry/sentry_test.go
generated
vendored
Normal file
|
@ -0,0 +1,97 @@
|
|||
package logrus_sentry
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/getsentry/raven-go"
|
||||
)
|
||||
|
||||
const (
|
||||
message = "error message"
|
||||
server_name = "testserver.internal"
|
||||
logger_name = "test.logger"
|
||||
)
|
||||
|
||||
func getTestLogger() *logrus.Logger {
|
||||
l := logrus.New()
|
||||
l.Out = ioutil.Discard
|
||||
return l
|
||||
}
|
||||
|
||||
func WithTestDSN(t *testing.T, tf func(string, <-chan *raven.Packet)) {
|
||||
pch := make(chan *raven.Packet, 1)
|
||||
s := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||
defer req.Body.Close()
|
||||
d := json.NewDecoder(req.Body)
|
||||
p := &raven.Packet{}
|
||||
err := d.Decode(p)
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
|
||||
pch <- p
|
||||
}))
|
||||
defer s.Close()
|
||||
|
||||
fragments := strings.SplitN(s.URL, "://", 2)
|
||||
dsn := fmt.Sprintf(
|
||||
"%s://public:secret@%s/sentry/project-id",
|
||||
fragments[0],
|
||||
fragments[1],
|
||||
)
|
||||
tf(dsn, pch)
|
||||
}
|
||||
|
||||
func TestSpecialFields(t *testing.T) {
|
||||
WithTestDSN(t, func(dsn string, pch <-chan *raven.Packet) {
|
||||
logger := getTestLogger()
|
||||
|
||||
hook, err := NewSentryHook(dsn, []logrus.Level{
|
||||
logrus.ErrorLevel,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
logger.Hooks.Add(hook)
|
||||
logger.WithFields(logrus.Fields{
|
||||
"server_name": server_name,
|
||||
"logger": logger_name,
|
||||
}).Error(message)
|
||||
|
||||
packet := <-pch
|
||||
if packet.Logger != logger_name {
|
||||
t.Errorf("logger should have been %s, was %s", logger_name, packet.Logger)
|
||||
}
|
||||
|
||||
if packet.ServerName != server_name {
|
||||
t.Errorf("server_name should have been %s, was %s", server_name, packet.ServerName)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestSentryHandler(t *testing.T) {
|
||||
WithTestDSN(t, func(dsn string, pch <-chan *raven.Packet) {
|
||||
logger := getTestLogger()
|
||||
hook, err := NewSentryHook(dsn, []logrus.Level{
|
||||
logrus.ErrorLevel,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
logger.Hooks.Add(hook)
|
||||
|
||||
logger.Error(message)
|
||||
packet := <-pch
|
||||
if packet.Message != message {
|
||||
t.Errorf("message should have been %s, was %s", message, packet.Message)
|
||||
}
|
||||
})
|
||||
}
|
20
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/syslog/README.md
generated
vendored
Normal file
20
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/syslog/README.md
generated
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
# Syslog Hooks for Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:"/>
|
||||
|
||||
## Usage
|
||||
|
||||
```go
|
||||
import (
|
||||
"log/syslog"
|
||||
"github.com/Sirupsen/logrus"
|
||||
logrus_syslog "github.com/Sirupsen/logrus/hooks/syslog"
|
||||
)
|
||||
|
||||
func main() {
|
||||
log := logrus.New()
|
||||
hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "")
|
||||
|
||||
if err == nil {
|
||||
log.Hooks.Add(hook)
|
||||
}
|
||||
}
|
||||
```
|
59
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/syslog/syslog.go
generated
vendored
Normal file
59
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/syslog/syslog.go
generated
vendored
Normal file
|
@ -0,0 +1,59 @@
|
|||
package logrus_syslog
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/Sirupsen/logrus"
|
||||
"log/syslog"
|
||||
"os"
|
||||
)
|
||||
|
||||
// SyslogHook to send logs via syslog.
|
||||
type SyslogHook struct {
|
||||
Writer *syslog.Writer
|
||||
SyslogNetwork string
|
||||
SyslogRaddr string
|
||||
}
|
||||
|
||||
// Creates a hook to be added to an instance of logger. This is called with
|
||||
// `hook, err := NewSyslogHook("udp", "localhost:514", syslog.LOG_DEBUG, "")`
|
||||
// `if err == nil { log.Hooks.Add(hook) }`
|
||||
func NewSyslogHook(network, raddr string, priority syslog.Priority, tag string) (*SyslogHook, error) {
|
||||
w, err := syslog.Dial(network, raddr, priority, tag)
|
||||
return &SyslogHook{w, network, raddr}, err
|
||||
}
|
||||
|
||||
func (hook *SyslogHook) Fire(entry *logrus.Entry) error {
|
||||
line, err := entry.String()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Unable to read entry, %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
switch entry.Level {
|
||||
case logrus.PanicLevel:
|
||||
return hook.Writer.Crit(line)
|
||||
case logrus.FatalLevel:
|
||||
return hook.Writer.Crit(line)
|
||||
case logrus.ErrorLevel:
|
||||
return hook.Writer.Err(line)
|
||||
case logrus.WarnLevel:
|
||||
return hook.Writer.Warning(line)
|
||||
case logrus.InfoLevel:
|
||||
return hook.Writer.Info(line)
|
||||
case logrus.DebugLevel:
|
||||
return hook.Writer.Debug(line)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (hook *SyslogHook) Levels() []logrus.Level {
|
||||
return []logrus.Level{
|
||||
logrus.PanicLevel,
|
||||
logrus.FatalLevel,
|
||||
logrus.ErrorLevel,
|
||||
logrus.WarnLevel,
|
||||
logrus.InfoLevel,
|
||||
logrus.DebugLevel,
|
||||
}
|
||||
}
|
26
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/syslog/syslog_test.go
generated
vendored
Normal file
26
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks/syslog/syslog_test.go
generated
vendored
Normal file
|
@ -0,0 +1,26 @@
|
|||
package logrus_syslog
|
||||
|
||||
import (
|
||||
"github.com/Sirupsen/logrus"
|
||||
"log/syslog"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestLocalhostAddAndPrint(t *testing.T) {
|
||||
log := logrus.New()
|
||||
hook, err := NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "")
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("Unable to connect to local syslog.")
|
||||
}
|
||||
|
||||
log.Hooks.Add(hook)
|
||||
|
||||
for _, level := range hook.Levels() {
|
||||
if len(log.Hooks[level]) != 1 {
|
||||
t.Errorf("SyslogHook was not added. The length of log.Hooks[%v]: %v", level, len(log.Hooks[level]))
|
||||
}
|
||||
}
|
||||
|
||||
log.Info("Congratulations!")
|
||||
}
|
26
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/json_formatter.go
generated
vendored
Normal file
26
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/json_formatter.go
generated
vendored
Normal file
|
@ -0,0 +1,26 @@
|
|||
package logrus
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
type JSONFormatter struct{}
|
||||
|
||||
func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
|
||||
data := make(Fields, len(entry.Data)+3)
|
||||
for k, v := range entry.Data {
|
||||
data[k] = v
|
||||
}
|
||||
prefixFieldClashes(data)
|
||||
data["time"] = entry.Time.Format(time.RFC3339)
|
||||
data["msg"] = entry.Message
|
||||
data["level"] = entry.Level.String()
|
||||
|
||||
serialized, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
|
||||
}
|
||||
return append(serialized, '\n'), nil
|
||||
}
|
161
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/logger.go
generated
vendored
Normal file
161
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/logger.go
generated
vendored
Normal file
|
@ -0,0 +1,161 @@
|
|||
package logrus
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type Logger struct {
|
||||
// The logs are `io.Copy`'d to this in a mutex. It's common to set this to a
|
||||
// file, or leave it default which is `os.Stdout`. You can also set this to
|
||||
// something more adventorous, such as logging to Kafka.
|
||||
Out io.Writer
|
||||
// Hooks for the logger instance. These allow firing events based on logging
|
||||
// levels and log entries. For example, to send errors to an error tracking
|
||||
// service, log to StatsD or dump the core on fatal errors.
|
||||
Hooks levelHooks
|
||||
// All log entries pass through the formatter before logged to Out. The
|
||||
// included formatters are `TextFormatter` and `JSONFormatter` for which
|
||||
// TextFormatter is the default. In development (when a TTY is attached) it
|
||||
// logs with colors, but to a file it wouldn't. You can easily implement your
|
||||
// own that implements the `Formatter` interface, see the `README` or included
|
||||
// formatters for examples.
|
||||
Formatter Formatter
|
||||
// The logging level the logger should log at. This is typically (and defaults
|
||||
// to) `logrus.Info`, which allows Info(), Warn(), Error() and Fatal() to be
|
||||
// logged. `logrus.Debug` is useful in
|
||||
Level Level
|
||||
// Used to sync writing to the log.
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
// Creates a new logger. Configuration should be set by changing `Formatter`,
|
||||
// `Out` and `Hooks` directly on the default logger instance. You can also just
|
||||
// instantiate your own:
|
||||
//
|
||||
// var log = &Logger{
|
||||
// Out: os.Stderr,
|
||||
// Formatter: new(JSONFormatter),
|
||||
// Hooks: make(levelHooks),
|
||||
// Level: logrus.DebugLevel,
|
||||
// }
|
||||
//
|
||||
// It's recommended to make this a global instance called `log`.
|
||||
func New() *Logger {
|
||||
return &Logger{
|
||||
Out: os.Stdout,
|
||||
Formatter: new(TextFormatter),
|
||||
Hooks: make(levelHooks),
|
||||
Level: InfoLevel,
|
||||
}
|
||||
}
|
||||
|
||||
// Adds a field to the log entry, note that you it doesn't log until you call
|
||||
// Debug, Print, Info, Warn, Fatal or Panic. It only creates a log entry.
|
||||
// Ff you want multiple fields, use `WithFields`.
|
||||
func (logger *Logger) WithField(key string, value interface{}) *Entry {
|
||||
return NewEntry(logger).WithField(key, value)
|
||||
}
|
||||
|
||||
// Adds a struct of fields to the log entry. All it does is call `WithField` for
|
||||
// each `Field`.
|
||||
func (logger *Logger) WithFields(fields Fields) *Entry {
|
||||
return NewEntry(logger).WithFields(fields)
|
||||
}
|
||||
|
||||
func (logger *Logger) Debugf(format string, args ...interface{}) {
|
||||
NewEntry(logger).Debugf(format, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Infof(format string, args ...interface{}) {
|
||||
NewEntry(logger).Infof(format, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Printf(format string, args ...interface{}) {
|
||||
NewEntry(logger).Printf(format, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Warnf(format string, args ...interface{}) {
|
||||
NewEntry(logger).Warnf(format, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Warningf(format string, args ...interface{}) {
|
||||
NewEntry(logger).Warnf(format, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Errorf(format string, args ...interface{}) {
|
||||
NewEntry(logger).Errorf(format, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Fatalf(format string, args ...interface{}) {
|
||||
NewEntry(logger).Fatalf(format, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Panicf(format string, args ...interface{}) {
|
||||
NewEntry(logger).Panicf(format, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Debug(args ...interface{}) {
|
||||
NewEntry(logger).Debug(args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Info(args ...interface{}) {
|
||||
NewEntry(logger).Info(args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Print(args ...interface{}) {
|
||||
NewEntry(logger).Info(args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Warn(args ...interface{}) {
|
||||
NewEntry(logger).Warn(args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Warning(args ...interface{}) {
|
||||
NewEntry(logger).Warn(args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Error(args ...interface{}) {
|
||||
NewEntry(logger).Error(args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Fatal(args ...interface{}) {
|
||||
NewEntry(logger).Fatal(args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Panic(args ...interface{}) {
|
||||
NewEntry(logger).Panic(args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Debugln(args ...interface{}) {
|
||||
NewEntry(logger).Debugln(args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Infoln(args ...interface{}) {
|
||||
NewEntry(logger).Infoln(args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Println(args ...interface{}) {
|
||||
NewEntry(logger).Println(args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Warnln(args ...interface{}) {
|
||||
NewEntry(logger).Warnln(args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Warningln(args ...interface{}) {
|
||||
NewEntry(logger).Warnln(args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Errorln(args ...interface{}) {
|
||||
NewEntry(logger).Errorln(args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Fatalln(args ...interface{}) {
|
||||
NewEntry(logger).Fatalln(args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Panicln(args ...interface{}) {
|
||||
NewEntry(logger).Panicln(args...)
|
||||
}
|
94
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/logrus.go
generated
vendored
Normal file
94
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/logrus.go
generated
vendored
Normal file
|
@ -0,0 +1,94 @@
|
|||
package logrus
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
)
|
||||
|
||||
// Fields type, used to pass to `WithFields`.
|
||||
type Fields map[string]interface{}
|
||||
|
||||
// Level type
|
||||
type Level uint8
|
||||
|
||||
// Convert the Level to a string. E.g. PanicLevel becomes "panic".
|
||||
func (level Level) String() string {
|
||||
switch level {
|
||||
case DebugLevel:
|
||||
return "debug"
|
||||
case InfoLevel:
|
||||
return "info"
|
||||
case WarnLevel:
|
||||
return "warning"
|
||||
case ErrorLevel:
|
||||
return "error"
|
||||
case FatalLevel:
|
||||
return "fatal"
|
||||
case PanicLevel:
|
||||
return "panic"
|
||||
}
|
||||
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
// ParseLevel takes a string level and returns the Logrus log level constant.
|
||||
func ParseLevel(lvl string) (Level, error) {
|
||||
switch lvl {
|
||||
case "panic":
|
||||
return PanicLevel, nil
|
||||
case "fatal":
|
||||
return FatalLevel, nil
|
||||
case "error":
|
||||
return ErrorLevel, nil
|
||||
case "warn", "warning":
|
||||
return WarnLevel, nil
|
||||
case "info":
|
||||
return InfoLevel, nil
|
||||
case "debug":
|
||||
return DebugLevel, nil
|
||||
}
|
||||
|
||||
var l Level
|
||||
return l, fmt.Errorf("not a valid logrus Level: %q", lvl)
|
||||
}
|
||||
|
||||
// These are the different logging levels. You can set the logging level to log
|
||||
// on your instance of logger, obtained with `logrus.New()`.
|
||||
const (
|
||||
// PanicLevel level, highest level of severity. Logs and then calls panic with the
|
||||
// message passed to Debug, Info, ...
|
||||
PanicLevel Level = iota
|
||||
// FatalLevel level. Logs and then calls `os.Exit(1)`. It will exit even if the
|
||||
// logging level is set to Panic.
|
||||
FatalLevel
|
||||
// ErrorLevel level. Logs. Used for errors that should definitely be noted.
|
||||
// Commonly used for hooks to send errors to an error tracking service.
|
||||
ErrorLevel
|
||||
// WarnLevel level. Non-critical entries that deserve eyes.
|
||||
WarnLevel
|
||||
// InfoLevel level. General operational entries about what's going on inside the
|
||||
// application.
|
||||
InfoLevel
|
||||
// DebugLevel level. Usually only enabled when debugging. Very verbose logging.
|
||||
DebugLevel
|
||||
)
|
||||
|
||||
// Won't compile if StdLogger can't be realized by a log.Logger
|
||||
var _ StdLogger = &log.Logger{}
|
||||
|
||||
// StdLogger is what your logrus-enabled library should take, that way
|
||||
// it'll accept a stdlib logger and a logrus logger. There's no standard
|
||||
// interface, this is the closest we get, unfortunately.
|
||||
type StdLogger interface {
|
||||
Print(...interface{})
|
||||
Printf(string, ...interface{})
|
||||
Println(...interface{})
|
||||
|
||||
Fatal(...interface{})
|
||||
Fatalf(string, ...interface{})
|
||||
Fatalln(...interface{})
|
||||
|
||||
Panic(...interface{})
|
||||
Panicf(string, ...interface{})
|
||||
Panicln(...interface{})
|
||||
}
|
283
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/logrus_test.go
generated
vendored
Normal file
283
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/logrus_test.go
generated
vendored
Normal file
|
@ -0,0 +1,283 @@
|
|||
package logrus
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func LogAndAssertJSON(t *testing.T, log func(*Logger), assertions func(fields Fields)) {
|
||||
var buffer bytes.Buffer
|
||||
var fields Fields
|
||||
|
||||
logger := New()
|
||||
logger.Out = &buffer
|
||||
logger.Formatter = new(JSONFormatter)
|
||||
|
||||
log(logger)
|
||||
|
||||
err := json.Unmarshal(buffer.Bytes(), &fields)
|
||||
assert.Nil(t, err)
|
||||
|
||||
assertions(fields)
|
||||
}
|
||||
|
||||
func LogAndAssertText(t *testing.T, log func(*Logger), assertions func(fields map[string]string)) {
|
||||
var buffer bytes.Buffer
|
||||
|
||||
logger := New()
|
||||
logger.Out = &buffer
|
||||
logger.Formatter = &TextFormatter{
|
||||
DisableColors: true,
|
||||
}
|
||||
|
||||
log(logger)
|
||||
|
||||
fields := make(map[string]string)
|
||||
for _, kv := range strings.Split(buffer.String(), " ") {
|
||||
if !strings.Contains(kv, "=") {
|
||||
continue
|
||||
}
|
||||
kvArr := strings.Split(kv, "=")
|
||||
key := strings.TrimSpace(kvArr[0])
|
||||
val := kvArr[1]
|
||||
if kvArr[1][0] == '"' {
|
||||
var err error
|
||||
val, err = strconv.Unquote(val)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
fields[key] = val
|
||||
}
|
||||
assertions(fields)
|
||||
}
|
||||
|
||||
func TestPrint(t *testing.T) {
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.Print("test")
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["msg"], "test")
|
||||
assert.Equal(t, fields["level"], "info")
|
||||
})
|
||||
}
|
||||
|
||||
func TestInfo(t *testing.T) {
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.Info("test")
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["msg"], "test")
|
||||
assert.Equal(t, fields["level"], "info")
|
||||
})
|
||||
}
|
||||
|
||||
func TestWarn(t *testing.T) {
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.Warn("test")
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["msg"], "test")
|
||||
assert.Equal(t, fields["level"], "warning")
|
||||
})
|
||||
}
|
||||
|
||||
func TestInfolnShouldAddSpacesBetweenStrings(t *testing.T) {
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.Infoln("test", "test")
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["msg"], "test test")
|
||||
})
|
||||
}
|
||||
|
||||
func TestInfolnShouldAddSpacesBetweenStringAndNonstring(t *testing.T) {
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.Infoln("test", 10)
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["msg"], "test 10")
|
||||
})
|
||||
}
|
||||
|
||||
func TestInfolnShouldAddSpacesBetweenTwoNonStrings(t *testing.T) {
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.Infoln(10, 10)
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["msg"], "10 10")
|
||||
})
|
||||
}
|
||||
|
||||
func TestInfoShouldAddSpacesBetweenTwoNonStrings(t *testing.T) {
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.Infoln(10, 10)
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["msg"], "10 10")
|
||||
})
|
||||
}
|
||||
|
||||
func TestInfoShouldNotAddSpacesBetweenStringAndNonstring(t *testing.T) {
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.Info("test", 10)
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["msg"], "test10")
|
||||
})
|
||||
}
|
||||
|
||||
func TestInfoShouldNotAddSpacesBetweenStrings(t *testing.T) {
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.Info("test", "test")
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["msg"], "testtest")
|
||||
})
|
||||
}
|
||||
|
||||
func TestWithFieldsShouldAllowAssignments(t *testing.T) {
|
||||
var buffer bytes.Buffer
|
||||
var fields Fields
|
||||
|
||||
logger := New()
|
||||
logger.Out = &buffer
|
||||
logger.Formatter = new(JSONFormatter)
|
||||
|
||||
localLog := logger.WithFields(Fields{
|
||||
"key1": "value1",
|
||||
})
|
||||
|
||||
localLog.WithField("key2", "value2").Info("test")
|
||||
err := json.Unmarshal(buffer.Bytes(), &fields)
|
||||
assert.Nil(t, err)
|
||||
|
||||
assert.Equal(t, "value2", fields["key2"])
|
||||
assert.Equal(t, "value1", fields["key1"])
|
||||
|
||||
buffer = bytes.Buffer{}
|
||||
fields = Fields{}
|
||||
localLog.Info("test")
|
||||
err = json.Unmarshal(buffer.Bytes(), &fields)
|
||||
assert.Nil(t, err)
|
||||
|
||||
_, ok := fields["key2"]
|
||||
assert.Equal(t, false, ok)
|
||||
assert.Equal(t, "value1", fields["key1"])
|
||||
}
|
||||
|
||||
func TestUserSuppliedFieldDoesNotOverwriteDefaults(t *testing.T) {
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.WithField("msg", "hello").Info("test")
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["msg"], "test")
|
||||
})
|
||||
}
|
||||
|
||||
func TestUserSuppliedMsgFieldHasPrefix(t *testing.T) {
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.WithField("msg", "hello").Info("test")
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["msg"], "test")
|
||||
assert.Equal(t, fields["fields.msg"], "hello")
|
||||
})
|
||||
}
|
||||
|
||||
func TestUserSuppliedTimeFieldHasPrefix(t *testing.T) {
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.WithField("time", "hello").Info("test")
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["fields.time"], "hello")
|
||||
})
|
||||
}
|
||||
|
||||
func TestUserSuppliedLevelFieldHasPrefix(t *testing.T) {
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.WithField("level", 1).Info("test")
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["level"], "info")
|
||||
assert.Equal(t, fields["fields.level"], 1)
|
||||
})
|
||||
}
|
||||
|
||||
func TestDefaultFieldsAreNotPrefixed(t *testing.T) {
|
||||
LogAndAssertText(t, func(log *Logger) {
|
||||
ll := log.WithField("herp", "derp")
|
||||
ll.Info("hello")
|
||||
ll.Info("bye")
|
||||
}, func(fields map[string]string) {
|
||||
for _, fieldName := range []string{"fields.level", "fields.time", "fields.msg"} {
|
||||
if _, ok := fields[fieldName]; ok {
|
||||
t.Fatalf("should not have prefixed %q: %v", fieldName, fields)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestDoubleLoggingDoesntPrefixPreviousFields(t *testing.T) {
|
||||
|
||||
var buffer bytes.Buffer
|
||||
var fields Fields
|
||||
|
||||
logger := New()
|
||||
logger.Out = &buffer
|
||||
logger.Formatter = new(JSONFormatter)
|
||||
|
||||
llog := logger.WithField("context", "eating raw fish")
|
||||
|
||||
llog.Info("looks delicious")
|
||||
|
||||
err := json.Unmarshal(buffer.Bytes(), &fields)
|
||||
assert.NoError(t, err, "should have decoded first message")
|
||||
assert.Equal(t, len(fields), 4, "should only have msg/time/level/context fields")
|
||||
assert.Equal(t, fields["msg"], "looks delicious")
|
||||
assert.Equal(t, fields["context"], "eating raw fish")
|
||||
|
||||
buffer.Reset()
|
||||
|
||||
llog.Warn("omg it is!")
|
||||
|
||||
err = json.Unmarshal(buffer.Bytes(), &fields)
|
||||
assert.NoError(t, err, "should have decoded second message")
|
||||
assert.Equal(t, len(fields), 4, "should only have msg/time/level/context fields")
|
||||
assert.Equal(t, fields["msg"], "omg it is!")
|
||||
assert.Equal(t, fields["context"], "eating raw fish")
|
||||
assert.Nil(t, fields["fields.msg"], "should not have prefixed previous `msg` entry")
|
||||
|
||||
}
|
||||
|
||||
func TestConvertLevelToString(t *testing.T) {
|
||||
assert.Equal(t, "debug", DebugLevel.String())
|
||||
assert.Equal(t, "info", InfoLevel.String())
|
||||
assert.Equal(t, "warning", WarnLevel.String())
|
||||
assert.Equal(t, "error", ErrorLevel.String())
|
||||
assert.Equal(t, "fatal", FatalLevel.String())
|
||||
assert.Equal(t, "panic", PanicLevel.String())
|
||||
}
|
||||
|
||||
func TestParseLevel(t *testing.T) {
|
||||
l, err := ParseLevel("panic")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, PanicLevel, l)
|
||||
|
||||
l, err = ParseLevel("fatal")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, FatalLevel, l)
|
||||
|
||||
l, err = ParseLevel("error")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, ErrorLevel, l)
|
||||
|
||||
l, err = ParseLevel("warn")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, WarnLevel, l)
|
||||
|
||||
l, err = ParseLevel("warning")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, WarnLevel, l)
|
||||
|
||||
l, err = ParseLevel("info")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, InfoLevel, l)
|
||||
|
||||
l, err = ParseLevel("debug")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, DebugLevel, l)
|
||||
|
||||
l, err = ParseLevel("invalid")
|
||||
assert.Equal(t, "not a valid logrus Level: \"invalid\"", err.Error())
|
||||
}
|
12
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/terminal_darwin.go
generated
vendored
Normal file
12
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/terminal_darwin.go
generated
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
// Based on ssh/terminal:
|
||||
// Copyright 2013 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 logrus
|
||||
|
||||
import "syscall"
|
||||
|
||||
const ioctlReadTermios = syscall.TIOCGETA
|
||||
|
||||
type Termios syscall.Termios
|
20
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/terminal_freebsd.go
generated
vendored
Normal file
20
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/terminal_freebsd.go
generated
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
Go 1.2 doesn't include Termios for FreeBSD. This should be added in 1.3 and this could be merged with terminal_darwin.
|
||||
*/
|
||||
package logrus
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
const ioctlReadTermios = syscall.TIOCGETA
|
||||
|
||||
type Termios struct {
|
||||
Iflag uint32
|
||||
Oflag uint32
|
||||
Cflag uint32
|
||||
Lflag uint32
|
||||
Cc [20]uint8
|
||||
Ispeed uint32
|
||||
Ospeed uint32
|
||||
}
|
12
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/terminal_linux.go
generated
vendored
Normal file
12
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/terminal_linux.go
generated
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
// Based on ssh/terminal:
|
||||
// Copyright 2013 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 logrus
|
||||
|
||||
import "syscall"
|
||||
|
||||
const ioctlReadTermios = syscall.TCGETS
|
||||
|
||||
type Termios syscall.Termios
|
21
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/terminal_notwindows.go
generated
vendored
Normal file
21
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/terminal_notwindows.go
generated
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
// Based on ssh/terminal:
|
||||
// Copyright 2011 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.
|
||||
|
||||
// +build linux,!appengine darwin freebsd openbsd
|
||||
|
||||
package logrus
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// IsTerminal returns true if the given file descriptor is a terminal.
|
||||
func IsTerminal() bool {
|
||||
fd := syscall.Stdout
|
||||
var termios Termios
|
||||
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
|
||||
return err == 0
|
||||
}
|
8
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/terminal_openbsd.go
generated
vendored
Normal file
8
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/terminal_openbsd.go
generated
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
|
||||
package logrus
|
||||
|
||||
import "syscall"
|
||||
|
||||
const ioctlReadTermios = syscall.TIOCGETA
|
||||
|
||||
type Termios syscall.Termios
|
27
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/terminal_windows.go
generated
vendored
Normal file
27
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/terminal_windows.go
generated
vendored
Normal file
|
@ -0,0 +1,27 @@
|
|||
// Based on ssh/terminal:
|
||||
// Copyright 2011 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.
|
||||
|
||||
// +build windows
|
||||
|
||||
package logrus
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var kernel32 = syscall.NewLazyDLL("kernel32.dll")
|
||||
|
||||
var (
|
||||
procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
|
||||
)
|
||||
|
||||
// IsTerminal returns true if the given file descriptor is a terminal.
|
||||
func IsTerminal() bool {
|
||||
fd := syscall.Stdout
|
||||
var st uint32
|
||||
r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
|
||||
return r != 0 && e == 0
|
||||
}
|
124
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/text_formatter.go
generated
vendored
Normal file
124
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/text_formatter.go
generated
vendored
Normal file
|
@ -0,0 +1,124 @@
|
|||
package logrus
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
nocolor = 0
|
||||
red = 31
|
||||
green = 32
|
||||
yellow = 33
|
||||
blue = 34
|
||||
)
|
||||
|
||||
var (
|
||||
baseTimestamp time.Time
|
||||
isTerminal bool
|
||||
noQuoteNeeded *regexp.Regexp
|
||||
)
|
||||
|
||||
func init() {
|
||||
baseTimestamp = time.Now()
|
||||
isTerminal = IsTerminal()
|
||||
}
|
||||
|
||||
func miniTS() int {
|
||||
return int(time.Since(baseTimestamp) / time.Second)
|
||||
}
|
||||
|
||||
type TextFormatter struct {
|
||||
// Set to true to bypass checking for a TTY before outputting colors.
|
||||
ForceColors bool
|
||||
DisableColors bool
|
||||
// Set to true to disable timestamp logging (useful when the output
|
||||
// is redirected to a logging system already adding a timestamp)
|
||||
DisableTimestamp bool
|
||||
}
|
||||
|
||||
func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
|
||||
|
||||
var keys []string
|
||||
for k := range entry.Data {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
b := &bytes.Buffer{}
|
||||
|
||||
prefixFieldClashes(entry.Data)
|
||||
|
||||
isColored := (f.ForceColors || isTerminal) && !f.DisableColors
|
||||
|
||||
if isColored {
|
||||
printColored(b, entry, keys)
|
||||
} else {
|
||||
if !f.DisableTimestamp {
|
||||
f.appendKeyValue(b, "time", entry.Time.Format(time.RFC3339))
|
||||
}
|
||||
f.appendKeyValue(b, "level", entry.Level.String())
|
||||
f.appendKeyValue(b, "msg", entry.Message)
|
||||
for _, key := range keys {
|
||||
f.appendKeyValue(b, key, entry.Data[key])
|
||||
}
|
||||
}
|
||||
|
||||
b.WriteByte('\n')
|
||||
return b.Bytes(), nil
|
||||
}
|
||||
|
||||
func printColored(b *bytes.Buffer, entry *Entry, keys []string) {
|
||||
var levelColor int
|
||||
switch entry.Level {
|
||||
case WarnLevel:
|
||||
levelColor = yellow
|
||||
case ErrorLevel, FatalLevel, PanicLevel:
|
||||
levelColor = red
|
||||
default:
|
||||
levelColor = blue
|
||||
}
|
||||
|
||||
levelText := strings.ToUpper(entry.Level.String())[0:4]
|
||||
|
||||
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, miniTS(), entry.Message)
|
||||
for _, k := range keys {
|
||||
v := entry.Data[k]
|
||||
fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=%v", levelColor, k, v)
|
||||
}
|
||||
}
|
||||
|
||||
func needsQuoting(text string) bool {
|
||||
for _, ch := range text {
|
||||
if !((ch >= 'a' && ch <= 'z') ||
|
||||
(ch >= 'A' && ch <= 'Z') ||
|
||||
(ch >= '0' && ch < '9') ||
|
||||
ch == '-' || ch == '.') {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key, value interface{}) {
|
||||
switch value.(type) {
|
||||
case string:
|
||||
if needsQuoting(value.(string)) {
|
||||
fmt.Fprintf(b, "%v=%s ", key, value)
|
||||
} else {
|
||||
fmt.Fprintf(b, "%v=%q ", key, value)
|
||||
}
|
||||
case error:
|
||||
if needsQuoting(value.(error).Error()) {
|
||||
fmt.Fprintf(b, "%v=%s ", key, value)
|
||||
} else {
|
||||
fmt.Fprintf(b, "%v=%q ", key, value)
|
||||
}
|
||||
default:
|
||||
fmt.Fprintf(b, "%v=%v ", key, value)
|
||||
}
|
||||
}
|
33
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/text_formatter_test.go
generated
vendored
Normal file
33
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/text_formatter_test.go
generated
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
package logrus
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestQuoting(t *testing.T) {
|
||||
tf := &TextFormatter{DisableColors: true}
|
||||
|
||||
checkQuoting := func(q bool, value interface{}) {
|
||||
b, _ := tf.Format(WithField("test", value))
|
||||
idx := bytes.Index(b, ([]byte)("test="))
|
||||
cont := bytes.Contains(b[idx+5:], []byte{'"'})
|
||||
if cont != q {
|
||||
if q {
|
||||
t.Errorf("quoting expected for: %#v", value)
|
||||
} else {
|
||||
t.Errorf("quoting not expected for: %#v", value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
checkQuoting(false, "abcd")
|
||||
checkQuoting(false, "v1.0")
|
||||
checkQuoting(true, "/foobar")
|
||||
checkQuoting(true, "x y")
|
||||
checkQuoting(true, "x,y")
|
||||
checkQuoting(false, errors.New("invalid"))
|
||||
checkQuoting(true, errors.New("invalid argument"))
|
||||
}
|
31
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/writer.go
generated
vendored
Normal file
31
libnetwork/Godeps/_workspace/src/github.com/Sirupsen/logrus/writer.go
generated
vendored
Normal file
|
@ -0,0 +1,31 @@
|
|||
package logrus
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"io"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
func (logger *Logger) Writer() (*io.PipeWriter) {
|
||||
reader, writer := io.Pipe()
|
||||
|
||||
go logger.writerScanner(reader)
|
||||
runtime.SetFinalizer(writer, writerFinalizer)
|
||||
|
||||
return writer
|
||||
}
|
||||
|
||||
func (logger *Logger) writerScanner(reader *io.PipeReader) {
|
||||
scanner := bufio.NewScanner(reader)
|
||||
for scanner.Scan() {
|
||||
logger.Print(scanner.Text())
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
logger.Errorf("Error while reading from Writer: %s", err)
|
||||
}
|
||||
reader.Close()
|
||||
}
|
||||
|
||||
func writerFinalizer(writer *io.PipeWriter) {
|
||||
writer.Close()
|
||||
}
|
720
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/bridge/driver.go
generated
vendored
Normal file
720
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/bridge/driver.go
generated
vendored
Normal file
|
@ -0,0 +1,720 @@
|
|||
package bridge
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/daemon/networkdriver"
|
||||
"github.com/docker/docker/daemon/networkdriver/ipallocator"
|
||||
"github.com/docker/docker/daemon/networkdriver/portmapper"
|
||||
"github.com/docker/docker/engine"
|
||||
"github.com/docker/docker/nat"
|
||||
"github.com/docker/docker/pkg/iptables"
|
||||
"github.com/docker/docker/pkg/networkfs/resolvconf"
|
||||
"github.com/docker/docker/pkg/parsers/kernel"
|
||||
"github.com/docker/libcontainer/netlink"
|
||||
)
|
||||
|
||||
const (
|
||||
DefaultNetworkBridge = "docker0"
|
||||
MaxAllocatedPortAttempts = 10
|
||||
)
|
||||
|
||||
// Network interface represents the networking stack of a container
|
||||
type networkInterface struct {
|
||||
IP net.IP
|
||||
IPv6 net.IP
|
||||
PortMappings []net.Addr // there are mappings to the host interfaces
|
||||
}
|
||||
|
||||
type ifaces struct {
|
||||
c map[string]*networkInterface
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
func (i *ifaces) Set(key string, n *networkInterface) {
|
||||
i.Lock()
|
||||
i.c[key] = n
|
||||
i.Unlock()
|
||||
}
|
||||
|
||||
func (i *ifaces) Get(key string) *networkInterface {
|
||||
i.Lock()
|
||||
res := i.c[key]
|
||||
i.Unlock()
|
||||
return res
|
||||
}
|
||||
|
||||
var (
|
||||
addrs = []string{
|
||||
// Here we don't follow the convention of using the 1st IP of the range for the gateway.
|
||||
// This is to use the same gateway IPs as the /24 ranges, which predate the /16 ranges.
|
||||
// In theory this shouldn't matter - in practice there's bound to be a few scripts relying
|
||||
// on the internal addressing or other stupid things like that.
|
||||
// They shouldn't, but hey, let's not break them unless we really have to.
|
||||
"172.17.42.1/16", // Don't use 172.16.0.0/16, it conflicts with EC2 DNS 172.16.0.23
|
||||
"10.0.42.1/16", // Don't even try using the entire /8, that's too intrusive
|
||||
"10.1.42.1/16",
|
||||
"10.42.42.1/16",
|
||||
"172.16.42.1/24",
|
||||
"172.16.43.1/24",
|
||||
"172.16.44.1/24",
|
||||
"10.0.42.1/24",
|
||||
"10.0.43.1/24",
|
||||
"192.168.42.1/24",
|
||||
"192.168.43.1/24",
|
||||
"192.168.44.1/24",
|
||||
}
|
||||
|
||||
bridgeIface string
|
||||
bridgeIPv4Network *net.IPNet
|
||||
bridgeIPv6Addr net.IP
|
||||
globalIPv6Network *net.IPNet
|
||||
|
||||
defaultBindingIP = net.ParseIP("0.0.0.0")
|
||||
currentInterfaces = ifaces{c: make(map[string]*networkInterface)}
|
||||
)
|
||||
|
||||
func InitDriver(job *engine.Job) engine.Status {
|
||||
var (
|
||||
networkv4 *net.IPNet
|
||||
networkv6 *net.IPNet
|
||||
addrv4 net.Addr
|
||||
addrsv6 []net.Addr
|
||||
enableIPTables = job.GetenvBool("EnableIptables")
|
||||
enableIPv6 = job.GetenvBool("EnableIPv6")
|
||||
icc = job.GetenvBool("InterContainerCommunication")
|
||||
ipMasq = job.GetenvBool("EnableIpMasq")
|
||||
ipForward = job.GetenvBool("EnableIpForward")
|
||||
bridgeIP = job.Getenv("BridgeIP")
|
||||
bridgeIPv6 = "fe80::1/64"
|
||||
fixedCIDR = job.Getenv("FixedCIDR")
|
||||
fixedCIDRv6 = job.Getenv("FixedCIDRv6")
|
||||
)
|
||||
|
||||
if defaultIP := job.Getenv("DefaultBindingIP"); defaultIP != "" {
|
||||
defaultBindingIP = net.ParseIP(defaultIP)
|
||||
}
|
||||
|
||||
bridgeIface = job.Getenv("BridgeIface")
|
||||
usingDefaultBridge := false
|
||||
if bridgeIface == "" {
|
||||
usingDefaultBridge = true
|
||||
bridgeIface = DefaultNetworkBridge
|
||||
}
|
||||
|
||||
addrv4, addrsv6, err := networkdriver.GetIfaceAddr(bridgeIface)
|
||||
|
||||
if err != nil {
|
||||
// No Bridge existent, create one
|
||||
// If we're not using the default bridge, fail without trying to create it
|
||||
if !usingDefaultBridge {
|
||||
return job.Error(err)
|
||||
}
|
||||
|
||||
// If the iface is not found, try to create it
|
||||
if err := configureBridge(bridgeIP, bridgeIPv6, enableIPv6); err != nil {
|
||||
return job.Error(err)
|
||||
}
|
||||
|
||||
addrv4, addrsv6, err = networkdriver.GetIfaceAddr(bridgeIface)
|
||||
if err != nil {
|
||||
return job.Error(err)
|
||||
}
|
||||
|
||||
if fixedCIDRv6 != "" {
|
||||
// Setting route to global IPv6 subnet
|
||||
log.Infof("Adding route to IPv6 network %q via device %q", fixedCIDRv6, bridgeIface)
|
||||
if err := netlink.AddRoute(fixedCIDRv6, "", "", bridgeIface); err != nil {
|
||||
log.Fatalf("Could not add route to IPv6 network %q via device %q", fixedCIDRv6, bridgeIface)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Bridge exists already, getting info...
|
||||
// validate that the bridge ip matches the ip specified by BridgeIP
|
||||
if bridgeIP != "" {
|
||||
networkv4 = addrv4.(*net.IPNet)
|
||||
bip, _, err := net.ParseCIDR(bridgeIP)
|
||||
if err != nil {
|
||||
return job.Error(err)
|
||||
}
|
||||
if !networkv4.IP.Equal(bip) {
|
||||
return job.Errorf("bridge ip (%s) does not match existing bridge configuration %s", networkv4.IP, bip)
|
||||
}
|
||||
}
|
||||
|
||||
// a bridge might exist but not have any IPv6 addr associated with it yet
|
||||
// (for example, an existing Docker installation that has only been used
|
||||
// with IPv4 and docker0 already is set up) In that case, we can perform
|
||||
// the bridge init for IPv6 here, else we will error out below if --ipv6=true
|
||||
if len(addrsv6) == 0 && enableIPv6 {
|
||||
if err := setupIPv6Bridge(bridgeIPv6); err != nil {
|
||||
return job.Error(err)
|
||||
}
|
||||
// recheck addresses now that IPv6 is setup on the bridge
|
||||
addrv4, addrsv6, err = networkdriver.GetIfaceAddr(bridgeIface)
|
||||
if err != nil {
|
||||
return job.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Check if route to fixedCIDRv6 is set
|
||||
}
|
||||
|
||||
if enableIPv6 {
|
||||
bip6, _, err := net.ParseCIDR(bridgeIPv6)
|
||||
if err != nil {
|
||||
return job.Error(err)
|
||||
}
|
||||
found := false
|
||||
for _, addrv6 := range addrsv6 {
|
||||
networkv6 = addrv6.(*net.IPNet)
|
||||
if networkv6.IP.Equal(bip6) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
return job.Errorf("bridge IPv6 does not match existing bridge configuration %s", bip6)
|
||||
}
|
||||
}
|
||||
|
||||
networkv4 = addrv4.(*net.IPNet)
|
||||
|
||||
if enableIPv6 {
|
||||
if len(addrsv6) == 0 {
|
||||
return job.Error(errors.New("IPv6 enabled but no IPv6 detected"))
|
||||
}
|
||||
bridgeIPv6Addr = networkv6.IP
|
||||
}
|
||||
|
||||
// Configure iptables for link support
|
||||
if enableIPTables {
|
||||
if err := setupIPTables(addrv4, icc, ipMasq); err != nil {
|
||||
return job.Error(err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ipForward {
|
||||
// Enable IPv4 forwarding
|
||||
if err := ioutil.WriteFile("/proc/sys/net/ipv4/ip_forward", []byte{'1', '\n'}, 0644); err != nil {
|
||||
job.Logf("WARNING: unable to enable IPv4 forwarding: %s\n", err)
|
||||
}
|
||||
|
||||
if fixedCIDRv6 != "" {
|
||||
// Enable IPv6 forwarding
|
||||
if err := ioutil.WriteFile("/proc/sys/net/ipv6/conf/default/forwarding", []byte{'1', '\n'}, 0644); err != nil {
|
||||
job.Logf("WARNING: unable to enable IPv6 default forwarding: %s\n", err)
|
||||
}
|
||||
if err := ioutil.WriteFile("/proc/sys/net/ipv6/conf/all/forwarding", []byte{'1', '\n'}, 0644); err != nil {
|
||||
job.Logf("WARNING: unable to enable IPv6 all forwarding: %s\n", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We can always try removing the iptables
|
||||
if err := iptables.RemoveExistingChain("DOCKER", iptables.Nat); err != nil {
|
||||
return job.Error(err)
|
||||
}
|
||||
|
||||
if enableIPTables {
|
||||
_, err := iptables.NewChain("DOCKER", bridgeIface, iptables.Nat)
|
||||
if err != nil {
|
||||
return job.Error(err)
|
||||
}
|
||||
chain, err := iptables.NewChain("DOCKER", bridgeIface, iptables.Filter)
|
||||
if err != nil {
|
||||
return job.Error(err)
|
||||
}
|
||||
portmapper.SetIptablesChain(chain)
|
||||
}
|
||||
|
||||
bridgeIPv4Network = networkv4
|
||||
if fixedCIDR != "" {
|
||||
_, subnet, err := net.ParseCIDR(fixedCIDR)
|
||||
if err != nil {
|
||||
return job.Error(err)
|
||||
}
|
||||
log.Debugf("Subnet: %v", subnet)
|
||||
if err := ipallocator.RegisterSubnet(bridgeIPv4Network, subnet); err != nil {
|
||||
return job.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
if fixedCIDRv6 != "" {
|
||||
_, subnet, err := net.ParseCIDR(fixedCIDRv6)
|
||||
if err != nil {
|
||||
return job.Error(err)
|
||||
}
|
||||
log.Debugf("Subnet: %v", subnet)
|
||||
if err := ipallocator.RegisterSubnet(subnet, subnet); err != nil {
|
||||
return job.Error(err)
|
||||
}
|
||||
globalIPv6Network = subnet
|
||||
}
|
||||
|
||||
// Block BridgeIP in IP allocator
|
||||
ipallocator.RequestIP(bridgeIPv4Network, bridgeIPv4Network.IP)
|
||||
|
||||
// https://github.com/docker/docker/issues/2768
|
||||
job.Eng.Hack_SetGlobalVar("httpapi.bridgeIP", bridgeIPv4Network.IP)
|
||||
|
||||
for name, f := range map[string]engine.Handler{
|
||||
"allocate_interface": Allocate,
|
||||
"release_interface": Release,
|
||||
"allocate_port": AllocatePort,
|
||||
"link": LinkContainers,
|
||||
} {
|
||||
if err := job.Eng.Register(name, f); err != nil {
|
||||
return job.Error(err)
|
||||
}
|
||||
}
|
||||
return engine.StatusOK
|
||||
}
|
||||
|
||||
func setupIPTables(addr net.Addr, icc, ipmasq bool) error {
|
||||
// Enable NAT
|
||||
|
||||
if ipmasq {
|
||||
natArgs := []string{"POSTROUTING", "-t", "nat", "-s", addr.String(), "!", "-o", bridgeIface, "-j", "MASQUERADE"}
|
||||
|
||||
if !iptables.Exists(natArgs...) {
|
||||
if output, err := iptables.Raw(append([]string{"-I"}, natArgs...)...); err != nil {
|
||||
return fmt.Errorf("Unable to enable network bridge NAT: %s", err)
|
||||
} else if len(output) != 0 {
|
||||
return &iptables.ChainError{Chain: "POSTROUTING", Output: output}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
args = []string{"FORWARD", "-i", bridgeIface, "-o", bridgeIface, "-j"}
|
||||
acceptArgs = append(args, "ACCEPT")
|
||||
dropArgs = append(args, "DROP")
|
||||
)
|
||||
|
||||
if !icc {
|
||||
iptables.Raw(append([]string{"-D"}, acceptArgs...)...)
|
||||
|
||||
if !iptables.Exists(dropArgs...) {
|
||||
log.Debugf("Disable inter-container communication")
|
||||
if output, err := iptables.Raw(append([]string{"-I"}, dropArgs...)...); err != nil {
|
||||
return fmt.Errorf("Unable to prevent intercontainer communication: %s", err)
|
||||
} else if len(output) != 0 {
|
||||
return fmt.Errorf("Error disabling intercontainer communication: %s", output)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
iptables.Raw(append([]string{"-D"}, dropArgs...)...)
|
||||
|
||||
if !iptables.Exists(acceptArgs...) {
|
||||
log.Debugf("Enable inter-container communication")
|
||||
if output, err := iptables.Raw(append([]string{"-I"}, acceptArgs...)...); err != nil {
|
||||
return fmt.Errorf("Unable to allow intercontainer communication: %s", err)
|
||||
} else if len(output) != 0 {
|
||||
return fmt.Errorf("Error enabling intercontainer communication: %s", output)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Accept all non-intercontainer outgoing packets
|
||||
outgoingArgs := []string{"FORWARD", "-i", bridgeIface, "!", "-o", bridgeIface, "-j", "ACCEPT"}
|
||||
if !iptables.Exists(outgoingArgs...) {
|
||||
if output, err := iptables.Raw(append([]string{"-I"}, outgoingArgs...)...); err != nil {
|
||||
return fmt.Errorf("Unable to allow outgoing packets: %s", err)
|
||||
} else if len(output) != 0 {
|
||||
return &iptables.ChainError{Chain: "FORWARD outgoing", Output: output}
|
||||
}
|
||||
}
|
||||
|
||||
// Accept incoming packets for existing connections
|
||||
existingArgs := []string{"FORWARD", "-o", bridgeIface, "-m", "conntrack", "--ctstate", "RELATED,ESTABLISHED", "-j", "ACCEPT"}
|
||||
|
||||
if !iptables.Exists(existingArgs...) {
|
||||
if output, err := iptables.Raw(append([]string{"-I"}, existingArgs...)...); err != nil {
|
||||
return fmt.Errorf("Unable to allow incoming packets: %s", err)
|
||||
} else if len(output) != 0 {
|
||||
return &iptables.ChainError{Chain: "FORWARD incoming", Output: output}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// configureBridge attempts to create and configure a network bridge interface named `bridgeIface` on the host
|
||||
// If bridgeIP is empty, it will try to find a non-conflicting IP from the Docker-specified private ranges
|
||||
// If the bridge `bridgeIface` already exists, it will only perform the IP address association with the existing
|
||||
// bridge (fixes issue #8444)
|
||||
// If an address which doesn't conflict with existing interfaces can't be found, an error is returned.
|
||||
func configureBridge(bridgeIP string, bridgeIPv6 string, enableIPv6 bool) error {
|
||||
nameservers := []string{}
|
||||
resolvConf, _ := resolvconf.Get()
|
||||
// we don't check for an error here, because we don't really care
|
||||
// if we can't read /etc/resolv.conf. So instead we skip the append
|
||||
// if resolvConf is nil. It either doesn't exist, or we can't read it
|
||||
// for some reason.
|
||||
if resolvConf != nil {
|
||||
nameservers = append(nameservers, resolvconf.GetNameserversAsCIDR(resolvConf)...)
|
||||
}
|
||||
|
||||
var ifaceAddr string
|
||||
if len(bridgeIP) != 0 {
|
||||
_, _, err := net.ParseCIDR(bridgeIP)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ifaceAddr = bridgeIP
|
||||
} else {
|
||||
for _, addr := range addrs {
|
||||
_, dockerNetwork, err := net.ParseCIDR(addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := networkdriver.CheckNameserverOverlaps(nameservers, dockerNetwork); err == nil {
|
||||
if err := networkdriver.CheckRouteOverlaps(dockerNetwork); err == nil {
|
||||
ifaceAddr = addr
|
||||
break
|
||||
} else {
|
||||
log.Debugf("%s %s", addr, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ifaceAddr == "" {
|
||||
return fmt.Errorf("Could not find a free IP address range for interface '%s'. Please configure its address manually and run 'docker -b %s'", bridgeIface, bridgeIface)
|
||||
}
|
||||
log.Debugf("Creating bridge %s with network %s", bridgeIface, ifaceAddr)
|
||||
|
||||
if err := createBridgeIface(bridgeIface); err != nil {
|
||||
// the bridge may already exist, therefore we can ignore an "exists" error
|
||||
if !os.IsExist(err) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
iface, err := net.InterfaceByName(bridgeIface)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ipAddr, ipNet, err := net.ParseCIDR(ifaceAddr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := netlink.NetworkLinkAddIp(iface, ipAddr, ipNet); err != nil {
|
||||
return fmt.Errorf("Unable to add private network: %s", err)
|
||||
}
|
||||
|
||||
if enableIPv6 {
|
||||
if err := setupIPv6Bridge(bridgeIPv6); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := netlink.NetworkLinkUp(iface); err != nil {
|
||||
return fmt.Errorf("Unable to start network bridge: %s", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func setupIPv6Bridge(bridgeIPv6 string) error {
|
||||
|
||||
iface, err := net.InterfaceByName(bridgeIface)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Enable IPv6 on the bridge
|
||||
procFile := "/proc/sys/net/ipv6/conf/" + iface.Name + "/disable_ipv6"
|
||||
if err := ioutil.WriteFile(procFile, []byte{'0', '\n'}, 0644); err != nil {
|
||||
return fmt.Errorf("Unable to enable IPv6 addresses on bridge: %v", err)
|
||||
}
|
||||
|
||||
ipAddr6, ipNet6, err := net.ParseCIDR(bridgeIPv6)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to parse bridge IPv6 address: %q, error: %v", bridgeIPv6, err)
|
||||
}
|
||||
|
||||
if err := netlink.NetworkLinkAddIp(iface, ipAddr6, ipNet6); err != nil {
|
||||
return fmt.Errorf("Unable to add private IPv6 network: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func createBridgeIface(name string) error {
|
||||
kv, err := kernel.GetKernelVersion()
|
||||
// only set the bridge's mac address if the kernel version is > 3.3
|
||||
// before that it was not supported
|
||||
setBridgeMacAddr := err == nil && (kv.Kernel >= 3 && kv.Major >= 3)
|
||||
log.Debugf("setting bridge mac address = %v", setBridgeMacAddr)
|
||||
return netlink.CreateBridge(name, setBridgeMacAddr)
|
||||
}
|
||||
|
||||
// Generate a IEEE802 compliant MAC address from the given IP address.
|
||||
//
|
||||
// The generator is guaranteed to be consistent: the same IP will always yield the same
|
||||
// MAC address. This is to avoid ARP cache issues.
|
||||
func generateMacAddr(ip net.IP) net.HardwareAddr {
|
||||
hw := make(net.HardwareAddr, 6)
|
||||
|
||||
// The first byte of the MAC address has to comply with these rules:
|
||||
// 1. Unicast: Set the least-significant bit to 0.
|
||||
// 2. Address is locally administered: Set the second-least-significant bit (U/L) to 1.
|
||||
// 3. As "small" as possible: The veth address has to be "smaller" than the bridge address.
|
||||
hw[0] = 0x02
|
||||
|
||||
// The first 24 bits of the MAC represent the Organizationally Unique Identifier (OUI).
|
||||
// Since this address is locally administered, we can do whatever we want as long as
|
||||
// it doesn't conflict with other addresses.
|
||||
hw[1] = 0x42
|
||||
|
||||
// Insert the IP address into the last 32 bits of the MAC address.
|
||||
// This is a simple way to guarantee the address will be consistent and unique.
|
||||
copy(hw[2:], ip.To4())
|
||||
|
||||
return hw
|
||||
}
|
||||
|
||||
func linkLocalIPv6FromMac(mac string) (string, error) {
|
||||
hx := strings.Replace(mac, ":", "", -1)
|
||||
hw, err := hex.DecodeString(hx)
|
||||
if err != nil {
|
||||
return "", errors.New("Could not parse MAC address " + mac)
|
||||
}
|
||||
|
||||
hw[0] ^= 0x2
|
||||
|
||||
return fmt.Sprintf("fe80::%x%x:%xff:fe%x:%x%x/64", hw[0], hw[1], hw[2], hw[3], hw[4], hw[5]), nil
|
||||
}
|
||||
|
||||
// Allocate a network interface
|
||||
func Allocate(job *engine.Job) engine.Status {
|
||||
var (
|
||||
ip net.IP
|
||||
mac net.HardwareAddr
|
||||
err error
|
||||
id = job.Args[0]
|
||||
requestedIP = net.ParseIP(job.Getenv("RequestedIP"))
|
||||
requestedIPv6 = net.ParseIP(job.Getenv("RequestedIPv6"))
|
||||
globalIPv6 net.IP
|
||||
)
|
||||
|
||||
if requestedIP != nil {
|
||||
ip, err = ipallocator.RequestIP(bridgeIPv4Network, requestedIP)
|
||||
} else {
|
||||
ip, err = ipallocator.RequestIP(bridgeIPv4Network, nil)
|
||||
}
|
||||
if err != nil {
|
||||
return job.Error(err)
|
||||
}
|
||||
|
||||
// If no explicit mac address was given, generate a random one.
|
||||
if mac, err = net.ParseMAC(job.Getenv("RequestedMac")); err != nil {
|
||||
mac = generateMacAddr(ip)
|
||||
}
|
||||
|
||||
if globalIPv6Network != nil {
|
||||
// if globalIPv6Network Size is at least a /80 subnet generate IPv6 address from MAC address
|
||||
netmask_ones, _ := globalIPv6Network.Mask.Size()
|
||||
if requestedIPv6 == nil && netmask_ones <= 80 {
|
||||
requestedIPv6 = globalIPv6Network.IP
|
||||
for i, h := range mac {
|
||||
requestedIPv6[i+10] = h
|
||||
}
|
||||
}
|
||||
|
||||
globalIPv6, err = ipallocator.RequestIP(globalIPv6Network, requestedIPv6)
|
||||
if err != nil {
|
||||
log.Errorf("Allocator: RequestIP v6: %s", err.Error())
|
||||
return job.Error(err)
|
||||
}
|
||||
log.Infof("Allocated IPv6 %s", globalIPv6)
|
||||
}
|
||||
|
||||
out := engine.Env{}
|
||||
out.Set("IP", ip.String())
|
||||
out.Set("Mask", bridgeIPv4Network.Mask.String())
|
||||
out.Set("Gateway", bridgeIPv4Network.IP.String())
|
||||
out.Set("MacAddress", mac.String())
|
||||
out.Set("Bridge", bridgeIface)
|
||||
|
||||
size, _ := bridgeIPv4Network.Mask.Size()
|
||||
out.SetInt("IPPrefixLen", size)
|
||||
|
||||
// if linklocal IPv6
|
||||
localIPv6Net, err := linkLocalIPv6FromMac(mac.String())
|
||||
if err != nil {
|
||||
return job.Error(err)
|
||||
}
|
||||
localIPv6, _, _ := net.ParseCIDR(localIPv6Net)
|
||||
out.Set("LinkLocalIPv6", localIPv6.String())
|
||||
out.Set("MacAddress", mac.String())
|
||||
|
||||
if globalIPv6Network != nil {
|
||||
out.Set("GlobalIPv6", globalIPv6.String())
|
||||
sizev6, _ := globalIPv6Network.Mask.Size()
|
||||
out.SetInt("GlobalIPv6PrefixLen", sizev6)
|
||||
out.Set("IPv6Gateway", bridgeIPv6Addr.String())
|
||||
}
|
||||
|
||||
currentInterfaces.Set(id, &networkInterface{
|
||||
IP: ip,
|
||||
IPv6: globalIPv6,
|
||||
})
|
||||
|
||||
out.WriteTo(job.Stdout)
|
||||
|
||||
return engine.StatusOK
|
||||
}
|
||||
|
||||
// release an interface for a select ip
|
||||
func Release(job *engine.Job) engine.Status {
|
||||
var (
|
||||
id = job.Args[0]
|
||||
containerInterface = currentInterfaces.Get(id)
|
||||
)
|
||||
|
||||
if containerInterface == nil {
|
||||
return job.Errorf("No network information to release for %s", id)
|
||||
}
|
||||
|
||||
for _, nat := range containerInterface.PortMappings {
|
||||
if err := portmapper.Unmap(nat); err != nil {
|
||||
log.Infof("Unable to unmap port %s: %s", nat, err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := ipallocator.ReleaseIP(bridgeIPv4Network, containerInterface.IP); err != nil {
|
||||
log.Infof("Unable to release IPv4 %s", err)
|
||||
}
|
||||
if globalIPv6Network != nil {
|
||||
if err := ipallocator.ReleaseIP(globalIPv6Network, containerInterface.IPv6); err != nil {
|
||||
log.Infof("Unable to release IPv6 %s", err)
|
||||
}
|
||||
}
|
||||
return engine.StatusOK
|
||||
}
|
||||
|
||||
// Allocate an external port and map it to the interface
|
||||
func AllocatePort(job *engine.Job) engine.Status {
|
||||
var (
|
||||
err error
|
||||
|
||||
ip = defaultBindingIP
|
||||
id = job.Args[0]
|
||||
hostIP = job.Getenv("HostIP")
|
||||
hostPort = job.GetenvInt("HostPort")
|
||||
containerPort = job.GetenvInt("ContainerPort")
|
||||
proto = job.Getenv("Proto")
|
||||
network = currentInterfaces.Get(id)
|
||||
)
|
||||
|
||||
if hostIP != "" {
|
||||
ip = net.ParseIP(hostIP)
|
||||
if ip == nil {
|
||||
return job.Errorf("Bad parameter: invalid host ip %s", hostIP)
|
||||
}
|
||||
}
|
||||
|
||||
// host ip, proto, and host port
|
||||
var container net.Addr
|
||||
switch proto {
|
||||
case "tcp":
|
||||
container = &net.TCPAddr{IP: network.IP, Port: containerPort}
|
||||
case "udp":
|
||||
container = &net.UDPAddr{IP: network.IP, Port: containerPort}
|
||||
default:
|
||||
return job.Errorf("unsupported address type %s", proto)
|
||||
}
|
||||
|
||||
//
|
||||
// Try up to 10 times to get a port that's not already allocated.
|
||||
//
|
||||
// In the event of failure to bind, return the error that portmapper.Map
|
||||
// yields.
|
||||
//
|
||||
|
||||
var host net.Addr
|
||||
for i := 0; i < MaxAllocatedPortAttempts; i++ {
|
||||
if host, err = portmapper.Map(container, ip, hostPort); err == nil {
|
||||
break
|
||||
}
|
||||
// There is no point in immediately retrying to map an explicitly
|
||||
// chosen port.
|
||||
if hostPort != 0 {
|
||||
job.Logf("Failed to allocate and map port %d: %s", hostPort, err)
|
||||
break
|
||||
}
|
||||
job.Logf("Failed to allocate and map port: %s, retry: %d", err, i+1)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return job.Error(err)
|
||||
}
|
||||
|
||||
network.PortMappings = append(network.PortMappings, host)
|
||||
|
||||
out := engine.Env{}
|
||||
switch netAddr := host.(type) {
|
||||
case *net.TCPAddr:
|
||||
out.Set("HostIP", netAddr.IP.String())
|
||||
out.SetInt("HostPort", netAddr.Port)
|
||||
case *net.UDPAddr:
|
||||
out.Set("HostIP", netAddr.IP.String())
|
||||
out.SetInt("HostPort", netAddr.Port)
|
||||
}
|
||||
if _, err := out.WriteTo(job.Stdout); err != nil {
|
||||
return job.Error(err)
|
||||
}
|
||||
|
||||
return engine.StatusOK
|
||||
}
|
||||
|
||||
func LinkContainers(job *engine.Job) engine.Status {
|
||||
var (
|
||||
action = job.Args[0]
|
||||
nfAction iptables.Action
|
||||
childIP = job.Getenv("ChildIP")
|
||||
parentIP = job.Getenv("ParentIP")
|
||||
ignoreErrors = job.GetenvBool("IgnoreErrors")
|
||||
ports = job.GetenvList("Ports")
|
||||
)
|
||||
|
||||
switch action {
|
||||
case "-A":
|
||||
nfAction = iptables.Append
|
||||
case "-I":
|
||||
nfAction = iptables.Insert
|
||||
case "-D":
|
||||
nfAction = iptables.Delete
|
||||
default:
|
||||
return job.Errorf("Invalid action '%s' specified", action)
|
||||
}
|
||||
|
||||
ip1 := net.ParseIP(parentIP)
|
||||
if ip1 == nil {
|
||||
return job.Errorf("parent IP '%s' is invalid", parentIP)
|
||||
}
|
||||
ip2 := net.ParseIP(childIP)
|
||||
if ip2 == nil {
|
||||
return job.Errorf("child IP '%s' is invalid", childIP)
|
||||
}
|
||||
|
||||
chain := iptables.Chain{Name: "DOCKER", Bridge: bridgeIface}
|
||||
for _, p := range ports {
|
||||
port := nat.Port(p)
|
||||
if err := chain.Link(nfAction, ip1, ip2, port.Int(), port.Proto()); !ignoreErrors && err != nil {
|
||||
return job.Error(err)
|
||||
}
|
||||
}
|
||||
return engine.StatusOK
|
||||
}
|
161
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/bridge/driver_test.go
generated
vendored
Normal file
161
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/bridge/driver_test.go
generated
vendored
Normal file
|
@ -0,0 +1,161 @@
|
|||
package bridge
|
||||
|
||||
import (
|
||||
"net"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/daemon/networkdriver/portmapper"
|
||||
"github.com/docker/docker/engine"
|
||||
"github.com/docker/docker/pkg/iptables"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// reset the new proxy command for mocking out the userland proxy in tests
|
||||
portmapper.NewProxy = portmapper.NewMockProxyCommand
|
||||
}
|
||||
|
||||
func findFreePort(t *testing.T) int {
|
||||
l, err := net.Listen("tcp", ":0")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to find a free port")
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
result, err := net.ResolveTCPAddr("tcp", l.Addr().String())
|
||||
if err != nil {
|
||||
t.Fatal("Failed to resolve address to identify free port")
|
||||
}
|
||||
return result.Port
|
||||
}
|
||||
|
||||
func newPortAllocationJob(eng *engine.Engine, port int) (job *engine.Job) {
|
||||
strPort := strconv.Itoa(port)
|
||||
|
||||
job = eng.Job("allocate_port", "container_id")
|
||||
job.Setenv("HostIP", "127.0.0.1")
|
||||
job.Setenv("HostPort", strPort)
|
||||
job.Setenv("Proto", "tcp")
|
||||
job.Setenv("ContainerPort", strPort)
|
||||
return
|
||||
}
|
||||
|
||||
func newPortAllocationJobWithInvalidHostIP(eng *engine.Engine, port int) (job *engine.Job) {
|
||||
strPort := strconv.Itoa(port)
|
||||
|
||||
job = eng.Job("allocate_port", "container_id")
|
||||
job.Setenv("HostIP", "localhost")
|
||||
job.Setenv("HostPort", strPort)
|
||||
job.Setenv("Proto", "tcp")
|
||||
job.Setenv("ContainerPort", strPort)
|
||||
return
|
||||
}
|
||||
|
||||
func TestAllocatePortDetection(t *testing.T) {
|
||||
eng := engine.New()
|
||||
eng.Logging = false
|
||||
|
||||
freePort := findFreePort(t)
|
||||
|
||||
// Init driver
|
||||
job := eng.Job("initdriver")
|
||||
if res := InitDriver(job); res != engine.StatusOK {
|
||||
t.Fatal("Failed to initialize network driver")
|
||||
}
|
||||
|
||||
// Allocate interface
|
||||
job = eng.Job("allocate_interface", "container_id")
|
||||
if res := Allocate(job); res != engine.StatusOK {
|
||||
t.Fatal("Failed to allocate network interface")
|
||||
}
|
||||
|
||||
// Allocate same port twice, expect failure on second call
|
||||
job = newPortAllocationJob(eng, freePort)
|
||||
if res := AllocatePort(job); res != engine.StatusOK {
|
||||
t.Fatal("Failed to find a free port to allocate")
|
||||
}
|
||||
if res := AllocatePort(job); res == engine.StatusOK {
|
||||
t.Fatal("Duplicate port allocation granted by AllocatePort")
|
||||
}
|
||||
}
|
||||
|
||||
func TestHostnameFormatChecking(t *testing.T) {
|
||||
eng := engine.New()
|
||||
eng.Logging = false
|
||||
|
||||
freePort := findFreePort(t)
|
||||
|
||||
// Init driver
|
||||
job := eng.Job("initdriver")
|
||||
if res := InitDriver(job); res != engine.StatusOK {
|
||||
t.Fatal("Failed to initialize network driver")
|
||||
}
|
||||
|
||||
// Allocate interface
|
||||
job = eng.Job("allocate_interface", "container_id")
|
||||
if res := Allocate(job); res != engine.StatusOK {
|
||||
t.Fatal("Failed to allocate network interface")
|
||||
}
|
||||
|
||||
// Allocate port with invalid HostIP, expect failure with Bad Request http status
|
||||
job = newPortAllocationJobWithInvalidHostIP(eng, freePort)
|
||||
if res := AllocatePort(job); res == engine.StatusOK {
|
||||
t.Fatal("Failed to check invalid HostIP")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMacAddrGeneration(t *testing.T) {
|
||||
ip := net.ParseIP("192.168.0.1")
|
||||
mac := generateMacAddr(ip).String()
|
||||
|
||||
// Should be consistent.
|
||||
if generateMacAddr(ip).String() != mac {
|
||||
t.Fatal("Inconsistent MAC address")
|
||||
}
|
||||
|
||||
// Should be unique.
|
||||
ip2 := net.ParseIP("192.168.0.2")
|
||||
if generateMacAddr(ip2).String() == mac {
|
||||
t.Fatal("Non-unique MAC address")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLinkContainers(t *testing.T) {
|
||||
eng := engine.New()
|
||||
eng.Logging = false
|
||||
|
||||
// Init driver
|
||||
job := eng.Job("initdriver")
|
||||
if res := InitDriver(job); res != engine.StatusOK {
|
||||
t.Fatal("Failed to initialize network driver")
|
||||
}
|
||||
|
||||
// Allocate interface
|
||||
job = eng.Job("allocate_interface", "container_id")
|
||||
if res := Allocate(job); res != engine.StatusOK {
|
||||
t.Fatal("Failed to allocate network interface")
|
||||
}
|
||||
|
||||
job.Args[0] = "-I"
|
||||
|
||||
job.Setenv("ChildIP", "172.17.0.2")
|
||||
job.Setenv("ParentIP", "172.17.0.1")
|
||||
job.SetenvBool("IgnoreErrors", false)
|
||||
job.SetenvList("Ports", []string{"1234"})
|
||||
|
||||
bridgeIface = "lo"
|
||||
_, err := iptables.NewChain("DOCKER", bridgeIface, iptables.Filter)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if res := LinkContainers(job); res != engine.StatusOK {
|
||||
t.Fatalf("LinkContainers failed")
|
||||
}
|
||||
|
||||
// flush rules
|
||||
if _, err = iptables.Raw([]string{"-F", "DOCKER"}...); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
}
|
160
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/ipallocator/allocator.go
generated
vendored
Normal file
160
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/ipallocator/allocator.go
generated
vendored
Normal file
|
@ -0,0 +1,160 @@
|
|||
package ipallocator
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math/big"
|
||||
"net"
|
||||
"sync"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/daemon/networkdriver"
|
||||
)
|
||||
|
||||
// allocatedMap is thread-unsafe set of allocated IP
|
||||
type allocatedMap struct {
|
||||
p map[string]struct{}
|
||||
last *big.Int
|
||||
begin *big.Int
|
||||
end *big.Int
|
||||
}
|
||||
|
||||
func newAllocatedMap(network *net.IPNet) *allocatedMap {
|
||||
firstIP, lastIP := networkdriver.NetworkRange(network)
|
||||
begin := big.NewInt(0).Add(ipToBigInt(firstIP), big.NewInt(1))
|
||||
end := big.NewInt(0).Sub(ipToBigInt(lastIP), big.NewInt(1))
|
||||
|
||||
return &allocatedMap{
|
||||
p: make(map[string]struct{}),
|
||||
begin: begin,
|
||||
end: end,
|
||||
last: big.NewInt(0).Sub(begin, big.NewInt(1)), // so first allocated will be begin
|
||||
}
|
||||
}
|
||||
|
||||
type networkSet map[string]*allocatedMap
|
||||
|
||||
var (
|
||||
ErrNoAvailableIPs = errors.New("no available ip addresses on network")
|
||||
ErrIPAlreadyAllocated = errors.New("ip already allocated")
|
||||
ErrIPOutOfRange = errors.New("requested ip is out of range")
|
||||
ErrNetworkAlreadyRegistered = errors.New("network already registered")
|
||||
ErrBadSubnet = errors.New("network does not contain specified subnet")
|
||||
)
|
||||
|
||||
var (
|
||||
lock = sync.Mutex{}
|
||||
allocatedIPs = networkSet{}
|
||||
)
|
||||
|
||||
// RegisterSubnet registers network in global allocator with bounds
|
||||
// defined by subnet. If you want to use network range you must call
|
||||
// this method before first RequestIP, otherwise full network range will be used
|
||||
func RegisterSubnet(network *net.IPNet, subnet *net.IPNet) error {
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
key := network.String()
|
||||
if _, ok := allocatedIPs[key]; ok {
|
||||
return ErrNetworkAlreadyRegistered
|
||||
}
|
||||
n := newAllocatedMap(network)
|
||||
beginIP, endIP := networkdriver.NetworkRange(subnet)
|
||||
begin := big.NewInt(0).Add(ipToBigInt(beginIP), big.NewInt(1))
|
||||
end := big.NewInt(0).Sub(ipToBigInt(endIP), big.NewInt(1))
|
||||
|
||||
// Check that subnet is within network
|
||||
if !(begin.Cmp(n.begin) >= 0 && end.Cmp(n.end) <= 0 && begin.Cmp(end) == -1) {
|
||||
return ErrBadSubnet
|
||||
}
|
||||
n.begin.Set(begin)
|
||||
n.end.Set(end)
|
||||
n.last.Sub(begin, big.NewInt(1))
|
||||
allocatedIPs[key] = n
|
||||
return nil
|
||||
}
|
||||
|
||||
// RequestIP requests an available ip from the given network. It
|
||||
// will return the next available ip if the ip provided is nil. If the
|
||||
// ip provided is not nil it will validate that the provided ip is available
|
||||
// for use or return an error
|
||||
func RequestIP(network *net.IPNet, ip net.IP) (net.IP, error) {
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
key := network.String()
|
||||
allocated, ok := allocatedIPs[key]
|
||||
if !ok {
|
||||
allocated = newAllocatedMap(network)
|
||||
allocatedIPs[key] = allocated
|
||||
}
|
||||
|
||||
if ip == nil {
|
||||
return allocated.getNextIP()
|
||||
}
|
||||
return allocated.checkIP(ip)
|
||||
}
|
||||
|
||||
// ReleaseIP adds the provided ip back into the pool of
|
||||
// available ips to be returned for use.
|
||||
func ReleaseIP(network *net.IPNet, ip net.IP) error {
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
if allocated, exists := allocatedIPs[network.String()]; exists {
|
||||
delete(allocated.p, ip.String())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (allocated *allocatedMap) checkIP(ip net.IP) (net.IP, error) {
|
||||
if _, ok := allocated.p[ip.String()]; ok {
|
||||
return nil, ErrIPAlreadyAllocated
|
||||
}
|
||||
|
||||
pos := ipToBigInt(ip)
|
||||
// Verify that the IP address is within our network range.
|
||||
if pos.Cmp(allocated.begin) == -1 || pos.Cmp(allocated.end) == 1 {
|
||||
return nil, ErrIPOutOfRange
|
||||
}
|
||||
|
||||
// Register the IP.
|
||||
allocated.p[ip.String()] = struct{}{}
|
||||
|
||||
return ip, nil
|
||||
}
|
||||
|
||||
// return an available ip if one is currently available. If not,
|
||||
// return the next available ip for the nextwork
|
||||
func (allocated *allocatedMap) getNextIP() (net.IP, error) {
|
||||
pos := big.NewInt(0).Set(allocated.last)
|
||||
allRange := big.NewInt(0).Sub(allocated.end, allocated.begin)
|
||||
for i := big.NewInt(0); i.Cmp(allRange) <= 0; i.Add(i, big.NewInt(1)) {
|
||||
pos.Add(pos, big.NewInt(1))
|
||||
if pos.Cmp(allocated.end) == 1 {
|
||||
pos.Set(allocated.begin)
|
||||
}
|
||||
if _, ok := allocated.p[bigIntToIP(pos).String()]; ok {
|
||||
continue
|
||||
}
|
||||
allocated.p[bigIntToIP(pos).String()] = struct{}{}
|
||||
allocated.last.Set(pos)
|
||||
return bigIntToIP(pos), nil
|
||||
}
|
||||
return nil, ErrNoAvailableIPs
|
||||
}
|
||||
|
||||
// Converts a 4 bytes IP into a 128 bit integer
|
||||
func ipToBigInt(ip net.IP) *big.Int {
|
||||
x := big.NewInt(0)
|
||||
if ip4 := ip.To4(); ip4 != nil {
|
||||
return x.SetBytes(ip4)
|
||||
}
|
||||
if ip6 := ip.To16(); ip6 != nil {
|
||||
return x.SetBytes(ip6)
|
||||
}
|
||||
|
||||
log.Errorf("ipToBigInt: Wrong IP length! %s", ip)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Converts 128 bit integer into a 4 bytes IP address
|
||||
func bigIntToIP(v *big.Int) net.IP {
|
||||
return net.IP(v.Bytes())
|
||||
}
|
681
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/ipallocator/allocator_test.go
generated
vendored
Normal file
681
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/ipallocator/allocator_test.go
generated
vendored
Normal file
|
@ -0,0 +1,681 @@
|
|||
package ipallocator
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"net"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func reset() {
|
||||
allocatedIPs = networkSet{}
|
||||
}
|
||||
|
||||
func TestConversion(t *testing.T) {
|
||||
ip := net.ParseIP("127.0.0.1")
|
||||
i := ipToBigInt(ip)
|
||||
if i.Cmp(big.NewInt(0x7f000001)) != 0 {
|
||||
t.Fatal("incorrect conversion")
|
||||
}
|
||||
conv := bigIntToIP(i)
|
||||
if !ip.Equal(conv) {
|
||||
t.Error(conv.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestConversionIPv6(t *testing.T) {
|
||||
ip := net.ParseIP("2a00:1450::1")
|
||||
ip2 := net.ParseIP("2a00:1450::2")
|
||||
ip3 := net.ParseIP("2a00:1450::1:1")
|
||||
i := ipToBigInt(ip)
|
||||
val, success := big.NewInt(0).SetString("2a001450000000000000000000000001", 16)
|
||||
if !success {
|
||||
t.Fatal("Hex-String to BigInt conversion failed.")
|
||||
}
|
||||
if i.Cmp(val) != 0 {
|
||||
t.Fatal("incorrent conversion")
|
||||
}
|
||||
|
||||
conv := bigIntToIP(i)
|
||||
conv2 := bigIntToIP(big.NewInt(0).Add(i, big.NewInt(1)))
|
||||
conv3 := bigIntToIP(big.NewInt(0).Add(i, big.NewInt(0x10000)))
|
||||
|
||||
if !ip.Equal(conv) {
|
||||
t.Error("2a00:1450::1 should be equal to " + conv.String())
|
||||
}
|
||||
if !ip2.Equal(conv2) {
|
||||
t.Error("2a00:1450::2 should be equal to " + conv2.String())
|
||||
}
|
||||
if !ip3.Equal(conv3) {
|
||||
t.Error("2a00:1450::1:1 should be equal to " + conv3.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestRequestNewIps(t *testing.T) {
|
||||
defer reset()
|
||||
network := &net.IPNet{
|
||||
IP: []byte{192, 168, 0, 1},
|
||||
Mask: []byte{255, 255, 255, 0},
|
||||
}
|
||||
|
||||
var ip net.IP
|
||||
var err error
|
||||
|
||||
for i := 1; i < 10; i++ {
|
||||
ip, err = RequestIP(network, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if expected := fmt.Sprintf("192.168.0.%d", i); ip.String() != expected {
|
||||
t.Fatalf("Expected ip %s got %s", expected, ip.String())
|
||||
}
|
||||
}
|
||||
value := bigIntToIP(big.NewInt(0).Add(ipToBigInt(ip), big.NewInt(1))).String()
|
||||
if err := ReleaseIP(network, ip); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ip, err = RequestIP(network, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if ip.String() != value {
|
||||
t.Fatalf("Expected to receive the next ip %s got %s", value, ip.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestRequestNewIpV6(t *testing.T) {
|
||||
defer reset()
|
||||
network := &net.IPNet{
|
||||
IP: []byte{0x2a, 0x00, 0x14, 0x50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||
Mask: []byte{255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0}, // /64 netmask
|
||||
}
|
||||
|
||||
var ip net.IP
|
||||
var err error
|
||||
for i := 1; i < 10; i++ {
|
||||
ip, err = RequestIP(network, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if expected := fmt.Sprintf("2a00:1450::%d", i); ip.String() != expected {
|
||||
t.Fatalf("Expected ip %s got %s", expected, ip.String())
|
||||
}
|
||||
}
|
||||
value := bigIntToIP(big.NewInt(0).Add(ipToBigInt(ip), big.NewInt(1))).String()
|
||||
if err := ReleaseIP(network, ip); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ip, err = RequestIP(network, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if ip.String() != value {
|
||||
t.Fatalf("Expected to receive the next ip %s got %s", value, ip.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestReleaseIp(t *testing.T) {
|
||||
defer reset()
|
||||
network := &net.IPNet{
|
||||
IP: []byte{192, 168, 0, 1},
|
||||
Mask: []byte{255, 255, 255, 0},
|
||||
}
|
||||
|
||||
ip, err := RequestIP(network, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := ReleaseIP(network, ip); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReleaseIpV6(t *testing.T) {
|
||||
defer reset()
|
||||
network := &net.IPNet{
|
||||
IP: []byte{0x2a, 0x00, 0x14, 0x50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||
Mask: []byte{255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0}, // /64 netmask
|
||||
}
|
||||
|
||||
ip, err := RequestIP(network, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := ReleaseIP(network, ip); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetReleasedIp(t *testing.T) {
|
||||
defer reset()
|
||||
network := &net.IPNet{
|
||||
IP: []byte{192, 168, 0, 1},
|
||||
Mask: []byte{255, 255, 255, 0},
|
||||
}
|
||||
|
||||
ip, err := RequestIP(network, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
value := ip.String()
|
||||
if err := ReleaseIP(network, ip); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for i := 0; i < 253; i++ {
|
||||
_, err = RequestIP(network, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = ReleaseIP(network, ip)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
ip, err = RequestIP(network, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if ip.String() != value {
|
||||
t.Fatalf("Expected to receive same ip %s got %s", value, ip.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetReleasedIpV6(t *testing.T) {
|
||||
defer reset()
|
||||
network := &net.IPNet{
|
||||
IP: []byte{0x2a, 0x00, 0x14, 0x50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||
Mask: []byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0},
|
||||
}
|
||||
|
||||
ip, err := RequestIP(network, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
value := ip.String()
|
||||
if err := ReleaseIP(network, ip); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for i := 0; i < 253; i++ {
|
||||
_, err = RequestIP(network, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = ReleaseIP(network, ip)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
ip, err = RequestIP(network, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if ip.String() != value {
|
||||
t.Fatalf("Expected to receive same ip %s got %s", value, ip.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestRequestSpecificIp(t *testing.T) {
|
||||
defer reset()
|
||||
network := &net.IPNet{
|
||||
IP: []byte{192, 168, 0, 1},
|
||||
Mask: []byte{255, 255, 255, 224},
|
||||
}
|
||||
|
||||
ip := net.ParseIP("192.168.0.5")
|
||||
|
||||
// Request a "good" IP.
|
||||
if _, err := RequestIP(network, ip); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Request the same IP again.
|
||||
if _, err := RequestIP(network, ip); err != ErrIPAlreadyAllocated {
|
||||
t.Fatalf("Got the same IP twice: %#v", err)
|
||||
}
|
||||
|
||||
// Request an out of range IP.
|
||||
if _, err := RequestIP(network, net.ParseIP("192.168.0.42")); err != ErrIPOutOfRange {
|
||||
t.Fatalf("Got an out of range IP: %#v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRequestSpecificIpV6(t *testing.T) {
|
||||
defer reset()
|
||||
network := &net.IPNet{
|
||||
IP: []byte{0x2a, 0x00, 0x14, 0x50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||
Mask: []byte{255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0}, // /64 netmask
|
||||
}
|
||||
|
||||
ip := net.ParseIP("2a00:1450::5")
|
||||
|
||||
// Request a "good" IP.
|
||||
if _, err := RequestIP(network, ip); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Request the same IP again.
|
||||
if _, err := RequestIP(network, ip); err != ErrIPAlreadyAllocated {
|
||||
t.Fatalf("Got the same IP twice: %#v", err)
|
||||
}
|
||||
|
||||
// Request an out of range IP.
|
||||
if _, err := RequestIP(network, net.ParseIP("2a00:1500::1")); err != ErrIPOutOfRange {
|
||||
t.Fatalf("Got an out of range IP: %#v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIPAllocator(t *testing.T) {
|
||||
expectedIPs := []net.IP{
|
||||
0: net.IPv4(127, 0, 0, 1),
|
||||
1: net.IPv4(127, 0, 0, 2),
|
||||
2: net.IPv4(127, 0, 0, 3),
|
||||
3: net.IPv4(127, 0, 0, 4),
|
||||
4: net.IPv4(127, 0, 0, 5),
|
||||
5: net.IPv4(127, 0, 0, 6),
|
||||
}
|
||||
|
||||
gwIP, n, _ := net.ParseCIDR("127.0.0.1/29")
|
||||
|
||||
network := &net.IPNet{IP: gwIP, Mask: n.Mask}
|
||||
// Pool after initialisation (f = free, u = used)
|
||||
// 1(f) - 2(f) - 3(f) - 4(f) - 5(f) - 6(f)
|
||||
// ↑
|
||||
|
||||
// Check that we get 6 IPs, from 127.0.0.1–127.0.0.6, in that
|
||||
// order.
|
||||
for i := 0; i < 6; i++ {
|
||||
ip, err := RequestIP(network, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
assertIPEquals(t, expectedIPs[i], ip)
|
||||
}
|
||||
// Before loop begin
|
||||
// 1(f) - 2(f) - 3(f) - 4(f) - 5(f) - 6(f)
|
||||
// ↑
|
||||
|
||||
// After i = 0
|
||||
// 1(u) - 2(f) - 3(f) - 4(f) - 5(f) - 6(f)
|
||||
// ↑
|
||||
|
||||
// After i = 1
|
||||
// 1(u) - 2(u) - 3(f) - 4(f) - 5(f) - 6(f)
|
||||
// ↑
|
||||
|
||||
// After i = 2
|
||||
// 1(u) - 2(u) - 3(u) - 4(f) - 5(f) - 6(f)
|
||||
// ↑
|
||||
|
||||
// After i = 3
|
||||
// 1(u) - 2(u) - 3(u) - 4(u) - 5(f) - 6(f)
|
||||
// ↑
|
||||
|
||||
// After i = 4
|
||||
// 1(u) - 2(u) - 3(u) - 4(u) - 5(u) - 6(f)
|
||||
// ↑
|
||||
|
||||
// After i = 5
|
||||
// 1(u) - 2(u) - 3(u) - 4(u) - 5(u) - 6(u)
|
||||
// ↑
|
||||
|
||||
// Check that there are no more IPs
|
||||
ip, err := RequestIP(network, nil)
|
||||
if err == nil {
|
||||
t.Fatalf("There shouldn't be any IP addresses at this point, got %s\n", ip)
|
||||
}
|
||||
|
||||
// Release some IPs in non-sequential order
|
||||
if err := ReleaseIP(network, expectedIPs[3]); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// 1(u) - 2(u) - 3(u) - 4(f) - 5(u) - 6(u)
|
||||
// ↑
|
||||
|
||||
if err := ReleaseIP(network, expectedIPs[2]); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// 1(u) - 2(u) - 3(f) - 4(f) - 5(u) - 6(u)
|
||||
// ↑
|
||||
|
||||
if err := ReleaseIP(network, expectedIPs[4]); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// 1(u) - 2(u) - 3(f) - 4(f) - 5(f) - 6(u)
|
||||
// ↑
|
||||
|
||||
// Make sure that IPs are reused in sequential order, starting
|
||||
// with the first released IP
|
||||
newIPs := make([]net.IP, 3)
|
||||
for i := 0; i < 3; i++ {
|
||||
ip, err := RequestIP(network, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
newIPs[i] = ip
|
||||
}
|
||||
assertIPEquals(t, expectedIPs[2], newIPs[0])
|
||||
assertIPEquals(t, expectedIPs[3], newIPs[1])
|
||||
assertIPEquals(t, expectedIPs[4], newIPs[2])
|
||||
|
||||
_, err = RequestIP(network, nil)
|
||||
if err == nil {
|
||||
t.Fatal("There shouldn't be any IP addresses at this point")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAllocateFirstIP(t *testing.T) {
|
||||
defer reset()
|
||||
network := &net.IPNet{
|
||||
IP: []byte{192, 168, 0, 0},
|
||||
Mask: []byte{255, 255, 255, 0},
|
||||
}
|
||||
|
||||
firstIP := network.IP.To4().Mask(network.Mask)
|
||||
first := big.NewInt(0).Add(ipToBigInt(firstIP), big.NewInt(1))
|
||||
|
||||
ip, err := RequestIP(network, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
allocated := ipToBigInt(ip)
|
||||
|
||||
if allocated == first {
|
||||
t.Fatalf("allocated ip should not equal first ip: %d == %d", first, allocated)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAllocateAllIps(t *testing.T) {
|
||||
defer reset()
|
||||
network := &net.IPNet{
|
||||
IP: []byte{192, 168, 0, 1},
|
||||
Mask: []byte{255, 255, 255, 0},
|
||||
}
|
||||
|
||||
var (
|
||||
current, first net.IP
|
||||
err error
|
||||
isFirst = true
|
||||
)
|
||||
|
||||
for err == nil {
|
||||
current, err = RequestIP(network, nil)
|
||||
if isFirst {
|
||||
first = current
|
||||
isFirst = false
|
||||
}
|
||||
}
|
||||
|
||||
if err != ErrNoAvailableIPs {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err := RequestIP(network, nil); err != ErrNoAvailableIPs {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := ReleaseIP(network, first); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
again, err := RequestIP(network, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
assertIPEquals(t, first, again)
|
||||
|
||||
// ensure that alloc.last == alloc.begin won't result in dead loop
|
||||
if _, err := RequestIP(network, nil); err != ErrNoAvailableIPs {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Test by making alloc.last the only free ip and ensure we get it back
|
||||
// #1. first of the range, (alloc.last == ipToInt(first) already)
|
||||
if err := ReleaseIP(network, first); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ret, err := RequestIP(network, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
assertIPEquals(t, first, ret)
|
||||
|
||||
// #2. last of the range, note that current is the last one
|
||||
last := net.IPv4(192, 168, 0, 254)
|
||||
setLastTo(t, network, last)
|
||||
|
||||
ret, err = RequestIP(network, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
assertIPEquals(t, last, ret)
|
||||
|
||||
// #3. middle of the range
|
||||
mid := net.IPv4(192, 168, 0, 7)
|
||||
setLastTo(t, network, mid)
|
||||
|
||||
ret, err = RequestIP(network, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
assertIPEquals(t, mid, ret)
|
||||
}
|
||||
|
||||
// make sure the pool is full when calling setLastTo.
|
||||
// we don't cheat here
|
||||
func setLastTo(t *testing.T, network *net.IPNet, ip net.IP) {
|
||||
if err := ReleaseIP(network, ip); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ret, err := RequestIP(network, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
assertIPEquals(t, ip, ret)
|
||||
|
||||
if err := ReleaseIP(network, ip); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAllocateDifferentSubnets(t *testing.T) {
|
||||
defer reset()
|
||||
network1 := &net.IPNet{
|
||||
IP: []byte{192, 168, 0, 1},
|
||||
Mask: []byte{255, 255, 255, 0},
|
||||
}
|
||||
network2 := &net.IPNet{
|
||||
IP: []byte{127, 0, 0, 1},
|
||||
Mask: []byte{255, 255, 255, 0},
|
||||
}
|
||||
network3 := &net.IPNet{
|
||||
IP: []byte{0x2a, 0x00, 0x14, 0x50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||
Mask: []byte{255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0}, // /64 netmask
|
||||
}
|
||||
network4 := &net.IPNet{
|
||||
IP: []byte{0x2a, 0x00, 0x16, 0x32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||
Mask: []byte{255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0}, // /64 netmask
|
||||
}
|
||||
expectedIPs := []net.IP{
|
||||
0: net.IPv4(192, 168, 0, 1),
|
||||
1: net.IPv4(192, 168, 0, 2),
|
||||
2: net.IPv4(127, 0, 0, 1),
|
||||
3: net.IPv4(127, 0, 0, 2),
|
||||
4: net.ParseIP("2a00:1450::1"),
|
||||
5: net.ParseIP("2a00:1450::2"),
|
||||
6: net.ParseIP("2a00:1450::3"),
|
||||
7: net.ParseIP("2a00:1632::1"),
|
||||
8: net.ParseIP("2a00:1632::2"),
|
||||
}
|
||||
|
||||
ip11, err := RequestIP(network1, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ip12, err := RequestIP(network1, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ip21, err := RequestIP(network2, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ip22, err := RequestIP(network2, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ip31, err := RequestIP(network3, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ip32, err := RequestIP(network3, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ip33, err := RequestIP(network3, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ip41, err := RequestIP(network4, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ip42, err := RequestIP(network4, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assertIPEquals(t, expectedIPs[0], ip11)
|
||||
assertIPEquals(t, expectedIPs[1], ip12)
|
||||
assertIPEquals(t, expectedIPs[2], ip21)
|
||||
assertIPEquals(t, expectedIPs[3], ip22)
|
||||
assertIPEquals(t, expectedIPs[4], ip31)
|
||||
assertIPEquals(t, expectedIPs[5], ip32)
|
||||
assertIPEquals(t, expectedIPs[6], ip33)
|
||||
assertIPEquals(t, expectedIPs[7], ip41)
|
||||
assertIPEquals(t, expectedIPs[8], ip42)
|
||||
}
|
||||
|
||||
func TestRegisterBadTwice(t *testing.T) {
|
||||
defer reset()
|
||||
network := &net.IPNet{
|
||||
IP: []byte{192, 168, 1, 1},
|
||||
Mask: []byte{255, 255, 255, 0},
|
||||
}
|
||||
subnet := &net.IPNet{
|
||||
IP: []byte{192, 168, 1, 8},
|
||||
Mask: []byte{255, 255, 255, 248},
|
||||
}
|
||||
|
||||
if err := RegisterSubnet(network, subnet); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
subnet = &net.IPNet{
|
||||
IP: []byte{192, 168, 1, 16},
|
||||
Mask: []byte{255, 255, 255, 248},
|
||||
}
|
||||
if err := RegisterSubnet(network, subnet); err != ErrNetworkAlreadyRegistered {
|
||||
t.Fatalf("Expecteded ErrNetworkAlreadyRegistered error, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegisterBadRange(t *testing.T) {
|
||||
defer reset()
|
||||
network := &net.IPNet{
|
||||
IP: []byte{192, 168, 1, 1},
|
||||
Mask: []byte{255, 255, 255, 0},
|
||||
}
|
||||
subnet := &net.IPNet{
|
||||
IP: []byte{192, 168, 1, 1},
|
||||
Mask: []byte{255, 255, 0, 0},
|
||||
}
|
||||
if err := RegisterSubnet(network, subnet); err != ErrBadSubnet {
|
||||
t.Fatalf("Expected ErrBadSubnet error, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAllocateFromRange(t *testing.T) {
|
||||
defer reset()
|
||||
network := &net.IPNet{
|
||||
IP: []byte{192, 168, 0, 1},
|
||||
Mask: []byte{255, 255, 255, 0},
|
||||
}
|
||||
// 192.168.1.9 - 192.168.1.14
|
||||
subnet := &net.IPNet{
|
||||
IP: []byte{192, 168, 0, 8},
|
||||
Mask: []byte{255, 255, 255, 248},
|
||||
}
|
||||
|
||||
if err := RegisterSubnet(network, subnet); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
expectedIPs := []net.IP{
|
||||
0: net.IPv4(192, 168, 0, 9),
|
||||
1: net.IPv4(192, 168, 0, 10),
|
||||
2: net.IPv4(192, 168, 0, 11),
|
||||
3: net.IPv4(192, 168, 0, 12),
|
||||
4: net.IPv4(192, 168, 0, 13),
|
||||
5: net.IPv4(192, 168, 0, 14),
|
||||
}
|
||||
for _, ip := range expectedIPs {
|
||||
rip, err := RequestIP(network, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assertIPEquals(t, ip, rip)
|
||||
}
|
||||
|
||||
if _, err := RequestIP(network, nil); err != ErrNoAvailableIPs {
|
||||
t.Fatalf("Expected ErrNoAvailableIPs error, got %v", err)
|
||||
}
|
||||
for _, ip := range expectedIPs {
|
||||
ReleaseIP(network, ip)
|
||||
rip, err := RequestIP(network, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assertIPEquals(t, ip, rip)
|
||||
}
|
||||
}
|
||||
|
||||
func assertIPEquals(t *testing.T, ip1, ip2 net.IP) {
|
||||
if !ip1.Equal(ip2) {
|
||||
t.Fatalf("Expected IP %s, got %s", ip1, ip2)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkRequestIP(b *testing.B) {
|
||||
network := &net.IPNet{
|
||||
IP: []byte{192, 168, 0, 1},
|
||||
Mask: []byte{255, 255, 255, 0},
|
||||
}
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
for j := 0; j < 253; j++ {
|
||||
_, err := RequestIP(network, nil)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
reset()
|
||||
}
|
||||
}
|
10
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/network.go
generated
vendored
Normal file
10
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/network.go
generated
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
package networkdriver
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrNetworkOverlapsWithNameservers = errors.New("requested network overlaps with nameserver")
|
||||
ErrNetworkOverlaps = errors.New("requested network overlaps with existing network")
|
||||
)
|
175
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/network_test.go
generated
vendored
Normal file
175
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/network_test.go
generated
vendored
Normal file
|
@ -0,0 +1,175 @@
|
|||
package networkdriver
|
||||
|
||||
import (
|
||||
"github.com/docker/libcontainer/netlink"
|
||||
"net"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNonOverlapingNameservers(t *testing.T) {
|
||||
network := &net.IPNet{
|
||||
IP: []byte{192, 168, 0, 1},
|
||||
Mask: []byte{255, 255, 255, 0},
|
||||
}
|
||||
nameservers := []string{
|
||||
"127.0.0.1/32",
|
||||
}
|
||||
|
||||
if err := CheckNameserverOverlaps(nameservers, network); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOverlapingNameservers(t *testing.T) {
|
||||
network := &net.IPNet{
|
||||
IP: []byte{192, 168, 0, 1},
|
||||
Mask: []byte{255, 255, 255, 0},
|
||||
}
|
||||
nameservers := []string{
|
||||
"192.168.0.1/32",
|
||||
}
|
||||
|
||||
if err := CheckNameserverOverlaps(nameservers, network); err == nil {
|
||||
t.Fatalf("Expected error %s got %s", ErrNetworkOverlapsWithNameservers, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCheckRouteOverlaps(t *testing.T) {
|
||||
orig := networkGetRoutesFct
|
||||
defer func() {
|
||||
networkGetRoutesFct = orig
|
||||
}()
|
||||
networkGetRoutesFct = func() ([]netlink.Route, error) {
|
||||
routesData := []string{"10.0.2.0/32", "10.0.3.0/24", "10.0.42.0/24", "172.16.42.0/24", "192.168.142.0/24"}
|
||||
|
||||
routes := []netlink.Route{}
|
||||
for _, addr := range routesData {
|
||||
_, netX, _ := net.ParseCIDR(addr)
|
||||
routes = append(routes, netlink.Route{IPNet: netX})
|
||||
}
|
||||
return routes, nil
|
||||
}
|
||||
|
||||
_, netX, _ := net.ParseCIDR("172.16.0.1/24")
|
||||
if err := CheckRouteOverlaps(netX); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, netX, _ = net.ParseCIDR("10.0.2.0/24")
|
||||
if err := CheckRouteOverlaps(netX); err == nil {
|
||||
t.Fatalf("10.0.2.0/24 and 10.0.2.0 should overlap but it doesn't")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCheckNameserverOverlaps(t *testing.T) {
|
||||
nameservers := []string{"10.0.2.3/32", "192.168.102.1/32"}
|
||||
|
||||
_, netX, _ := net.ParseCIDR("10.0.2.3/32")
|
||||
|
||||
if err := CheckNameserverOverlaps(nameservers, netX); err == nil {
|
||||
t.Fatalf("%s should overlap 10.0.2.3/32 but doesn't", netX)
|
||||
}
|
||||
|
||||
_, netX, _ = net.ParseCIDR("192.168.102.2/32")
|
||||
|
||||
if err := CheckNameserverOverlaps(nameservers, netX); err != nil {
|
||||
t.Fatalf("%s should not overlap %v but it does", netX, nameservers)
|
||||
}
|
||||
}
|
||||
|
||||
func AssertOverlap(CIDRx string, CIDRy string, t *testing.T) {
|
||||
_, netX, _ := net.ParseCIDR(CIDRx)
|
||||
_, netY, _ := net.ParseCIDR(CIDRy)
|
||||
if !NetworkOverlaps(netX, netY) {
|
||||
t.Errorf("%v and %v should overlap", netX, netY)
|
||||
}
|
||||
}
|
||||
|
||||
func AssertNoOverlap(CIDRx string, CIDRy string, t *testing.T) {
|
||||
_, netX, _ := net.ParseCIDR(CIDRx)
|
||||
_, netY, _ := net.ParseCIDR(CIDRy)
|
||||
if NetworkOverlaps(netX, netY) {
|
||||
t.Errorf("%v and %v should not overlap", netX, netY)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNetworkOverlaps(t *testing.T) {
|
||||
//netY starts at same IP and ends within netX
|
||||
AssertOverlap("172.16.0.1/24", "172.16.0.1/25", t)
|
||||
//netY starts within netX and ends at same IP
|
||||
AssertOverlap("172.16.0.1/24", "172.16.0.128/25", t)
|
||||
//netY starts and ends within netX
|
||||
AssertOverlap("172.16.0.1/24", "172.16.0.64/25", t)
|
||||
//netY starts at same IP and ends outside of netX
|
||||
AssertOverlap("172.16.0.1/24", "172.16.0.1/23", t)
|
||||
//netY starts before and ends at same IP of netX
|
||||
AssertOverlap("172.16.1.1/24", "172.16.0.1/23", t)
|
||||
//netY starts before and ends outside of netX
|
||||
AssertOverlap("172.16.1.1/24", "172.16.0.1/22", t)
|
||||
//netY starts and ends before netX
|
||||
AssertNoOverlap("172.16.1.1/25", "172.16.0.1/24", t)
|
||||
//netX starts and ends before netY
|
||||
AssertNoOverlap("172.16.1.1/25", "172.16.2.1/24", t)
|
||||
}
|
||||
|
||||
func TestNetworkRange(t *testing.T) {
|
||||
// Simple class C test
|
||||
_, network, _ := net.ParseCIDR("192.168.0.1/24")
|
||||
first, last := NetworkRange(network)
|
||||
if !first.Equal(net.ParseIP("192.168.0.0")) {
|
||||
t.Error(first.String())
|
||||
}
|
||||
if !last.Equal(net.ParseIP("192.168.0.255")) {
|
||||
t.Error(last.String())
|
||||
}
|
||||
|
||||
// Class A test
|
||||
_, network, _ = net.ParseCIDR("10.0.0.1/8")
|
||||
first, last = NetworkRange(network)
|
||||
if !first.Equal(net.ParseIP("10.0.0.0")) {
|
||||
t.Error(first.String())
|
||||
}
|
||||
if !last.Equal(net.ParseIP("10.255.255.255")) {
|
||||
t.Error(last.String())
|
||||
}
|
||||
|
||||
// Class A, random IP address
|
||||
_, network, _ = net.ParseCIDR("10.1.2.3/8")
|
||||
first, last = NetworkRange(network)
|
||||
if !first.Equal(net.ParseIP("10.0.0.0")) {
|
||||
t.Error(first.String())
|
||||
}
|
||||
if !last.Equal(net.ParseIP("10.255.255.255")) {
|
||||
t.Error(last.String())
|
||||
}
|
||||
|
||||
// 32bit mask
|
||||
_, network, _ = net.ParseCIDR("10.1.2.3/32")
|
||||
first, last = NetworkRange(network)
|
||||
if !first.Equal(net.ParseIP("10.1.2.3")) {
|
||||
t.Error(first.String())
|
||||
}
|
||||
if !last.Equal(net.ParseIP("10.1.2.3")) {
|
||||
t.Error(last.String())
|
||||
}
|
||||
|
||||
// 31bit mask
|
||||
_, network, _ = net.ParseCIDR("10.1.2.3/31")
|
||||
first, last = NetworkRange(network)
|
||||
if !first.Equal(net.ParseIP("10.1.2.2")) {
|
||||
t.Error(first.String())
|
||||
}
|
||||
if !last.Equal(net.ParseIP("10.1.2.3")) {
|
||||
t.Error(last.String())
|
||||
}
|
||||
|
||||
// 26bit mask
|
||||
_, network, _ = net.ParseCIDR("10.1.2.3/26")
|
||||
first, last = NetworkRange(network)
|
||||
if !first.Equal(net.ParseIP("10.1.2.0")) {
|
||||
t.Error(first.String())
|
||||
}
|
||||
if !last.Equal(net.ParseIP("10.1.2.63")) {
|
||||
t.Error(last.String())
|
||||
}
|
||||
}
|
153
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/portallocator/portallocator.go
generated
vendored
Normal file
153
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/portallocator/portallocator.go
generated
vendored
Normal file
|
@ -0,0 +1,153 @@
|
|||
package portallocator
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type portMap struct {
|
||||
p map[int]struct{}
|
||||
last int
|
||||
}
|
||||
|
||||
func newPortMap() *portMap {
|
||||
return &portMap{
|
||||
p: map[int]struct{}{},
|
||||
last: EndPortRange,
|
||||
}
|
||||
}
|
||||
|
||||
type protoMap map[string]*portMap
|
||||
|
||||
func newProtoMap() protoMap {
|
||||
return protoMap{
|
||||
"tcp": newPortMap(),
|
||||
"udp": newPortMap(),
|
||||
}
|
||||
}
|
||||
|
||||
type ipMapping map[string]protoMap
|
||||
|
||||
const (
|
||||
BeginPortRange = 49153
|
||||
EndPortRange = 65535
|
||||
)
|
||||
|
||||
var (
|
||||
ErrAllPortsAllocated = errors.New("all ports are allocated")
|
||||
ErrUnknownProtocol = errors.New("unknown protocol")
|
||||
)
|
||||
|
||||
var (
|
||||
mutex sync.Mutex
|
||||
|
||||
defaultIP = net.ParseIP("0.0.0.0")
|
||||
globalMap = ipMapping{}
|
||||
)
|
||||
|
||||
type ErrPortAlreadyAllocated struct {
|
||||
ip string
|
||||
port int
|
||||
}
|
||||
|
||||
func NewErrPortAlreadyAllocated(ip string, port int) ErrPortAlreadyAllocated {
|
||||
return ErrPortAlreadyAllocated{
|
||||
ip: ip,
|
||||
port: port,
|
||||
}
|
||||
}
|
||||
|
||||
func (e ErrPortAlreadyAllocated) IP() string {
|
||||
return e.ip
|
||||
}
|
||||
|
||||
func (e ErrPortAlreadyAllocated) Port() int {
|
||||
return e.port
|
||||
}
|
||||
|
||||
func (e ErrPortAlreadyAllocated) IPPort() string {
|
||||
return fmt.Sprintf("%s:%d", e.ip, e.port)
|
||||
}
|
||||
|
||||
func (e ErrPortAlreadyAllocated) Error() string {
|
||||
return fmt.Sprintf("Bind for %s:%d failed: port is already allocated", e.ip, e.port)
|
||||
}
|
||||
|
||||
// RequestPort requests new port from global ports pool for specified ip and proto.
|
||||
// If port is 0 it returns first free port. Otherwise it cheks port availability
|
||||
// in pool and return that port or error if port is already busy.
|
||||
func RequestPort(ip net.IP, proto string, port int) (int, error) {
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
|
||||
if proto != "tcp" && proto != "udp" {
|
||||
return 0, ErrUnknownProtocol
|
||||
}
|
||||
|
||||
if ip == nil {
|
||||
ip = defaultIP
|
||||
}
|
||||
ipstr := ip.String()
|
||||
protomap, ok := globalMap[ipstr]
|
||||
if !ok {
|
||||
protomap = newProtoMap()
|
||||
globalMap[ipstr] = protomap
|
||||
}
|
||||
mapping := protomap[proto]
|
||||
if port > 0 {
|
||||
if _, ok := mapping.p[port]; !ok {
|
||||
mapping.p[port] = struct{}{}
|
||||
return port, nil
|
||||
}
|
||||
return 0, NewErrPortAlreadyAllocated(ipstr, port)
|
||||
}
|
||||
|
||||
port, err := mapping.findPort()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return port, nil
|
||||
}
|
||||
|
||||
// ReleasePort releases port from global ports pool for specified ip and proto.
|
||||
func ReleasePort(ip net.IP, proto string, port int) error {
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
|
||||
if ip == nil {
|
||||
ip = defaultIP
|
||||
}
|
||||
protomap, ok := globalMap[ip.String()]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
delete(protomap[proto].p, port)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReleaseAll releases all ports for all ips.
|
||||
func ReleaseAll() error {
|
||||
mutex.Lock()
|
||||
globalMap = ipMapping{}
|
||||
mutex.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pm *portMap) findPort() (int, error) {
|
||||
port := pm.last
|
||||
for i := 0; i <= EndPortRange-BeginPortRange; i++ {
|
||||
port++
|
||||
if port > EndPortRange {
|
||||
port = BeginPortRange
|
||||
}
|
||||
|
||||
if _, ok := pm.p[port]; !ok {
|
||||
pm.p[port] = struct{}{}
|
||||
pm.last = port
|
||||
return port, nil
|
||||
}
|
||||
}
|
||||
return 0, ErrAllPortsAllocated
|
||||
}
|
245
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/portallocator/portallocator_test.go
generated
vendored
Normal file
245
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/portallocator/portallocator_test.go
generated
vendored
Normal file
|
@ -0,0 +1,245 @@
|
|||
package portallocator
|
||||
|
||||
import (
|
||||
"net"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func reset() {
|
||||
ReleaseAll()
|
||||
}
|
||||
|
||||
func TestRequestNewPort(t *testing.T) {
|
||||
defer reset()
|
||||
|
||||
port, err := RequestPort(defaultIP, "tcp", 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if expected := BeginPortRange; port != expected {
|
||||
t.Fatalf("Expected port %d got %d", expected, port)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRequestSpecificPort(t *testing.T) {
|
||||
defer reset()
|
||||
|
||||
port, err := RequestPort(defaultIP, "tcp", 5000)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if port != 5000 {
|
||||
t.Fatalf("Expected port 5000 got %d", port)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReleasePort(t *testing.T) {
|
||||
defer reset()
|
||||
|
||||
port, err := RequestPort(defaultIP, "tcp", 5000)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if port != 5000 {
|
||||
t.Fatalf("Expected port 5000 got %d", port)
|
||||
}
|
||||
|
||||
if err := ReleasePort(defaultIP, "tcp", 5000); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReuseReleasedPort(t *testing.T) {
|
||||
defer reset()
|
||||
|
||||
port, err := RequestPort(defaultIP, "tcp", 5000)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if port != 5000 {
|
||||
t.Fatalf("Expected port 5000 got %d", port)
|
||||
}
|
||||
|
||||
if err := ReleasePort(defaultIP, "tcp", 5000); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
port, err = RequestPort(defaultIP, "tcp", 5000)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReleaseUnreadledPort(t *testing.T) {
|
||||
defer reset()
|
||||
|
||||
port, err := RequestPort(defaultIP, "tcp", 5000)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if port != 5000 {
|
||||
t.Fatalf("Expected port 5000 got %d", port)
|
||||
}
|
||||
|
||||
port, err = RequestPort(defaultIP, "tcp", 5000)
|
||||
|
||||
switch err.(type) {
|
||||
case ErrPortAlreadyAllocated:
|
||||
default:
|
||||
t.Fatalf("Expected port allocation error got %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnknowProtocol(t *testing.T) {
|
||||
defer reset()
|
||||
|
||||
if _, err := RequestPort(defaultIP, "tcpp", 0); err != ErrUnknownProtocol {
|
||||
t.Fatalf("Expected error %s got %s", ErrUnknownProtocol, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAllocateAllPorts(t *testing.T) {
|
||||
defer reset()
|
||||
|
||||
for i := 0; i <= EndPortRange-BeginPortRange; i++ {
|
||||
port, err := RequestPort(defaultIP, "tcp", 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if expected := BeginPortRange + i; port != expected {
|
||||
t.Fatalf("Expected port %d got %d", expected, port)
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := RequestPort(defaultIP, "tcp", 0); err != ErrAllPortsAllocated {
|
||||
t.Fatalf("Expected error %s got %s", ErrAllPortsAllocated, err)
|
||||
}
|
||||
|
||||
_, err := RequestPort(defaultIP, "udp", 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// release a port in the middle and ensure we get another tcp port
|
||||
port := BeginPortRange + 5
|
||||
if err := ReleasePort(defaultIP, "tcp", port); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
newPort, err := RequestPort(defaultIP, "tcp", 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if newPort != port {
|
||||
t.Fatalf("Expected port %d got %d", port, newPort)
|
||||
}
|
||||
|
||||
// now pm.last == newPort, release it so that it's the only free port of
|
||||
// the range, and ensure we get it back
|
||||
if err := ReleasePort(defaultIP, "tcp", newPort); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
port, err = RequestPort(defaultIP, "tcp", 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if newPort != port {
|
||||
t.Fatalf("Expected port %d got %d", newPort, port)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkAllocatePorts(b *testing.B) {
|
||||
defer reset()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
for i := 0; i <= EndPortRange-BeginPortRange; i++ {
|
||||
port, err := RequestPort(defaultIP, "tcp", 0)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
if expected := BeginPortRange + i; port != expected {
|
||||
b.Fatalf("Expected port %d got %d", expected, port)
|
||||
}
|
||||
}
|
||||
reset()
|
||||
}
|
||||
}
|
||||
|
||||
func TestPortAllocation(t *testing.T) {
|
||||
defer reset()
|
||||
|
||||
ip := net.ParseIP("192.168.0.1")
|
||||
ip2 := net.ParseIP("192.168.0.2")
|
||||
if port, err := RequestPort(ip, "tcp", 80); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if port != 80 {
|
||||
t.Fatalf("Acquire(80) should return 80, not %d", port)
|
||||
}
|
||||
port, err := RequestPort(ip, "tcp", 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if port <= 0 {
|
||||
t.Fatalf("Acquire(0) should return a non-zero port")
|
||||
}
|
||||
|
||||
if _, err := RequestPort(ip, "tcp", port); err == nil {
|
||||
t.Fatalf("Acquiring a port already in use should return an error")
|
||||
}
|
||||
|
||||
if newPort, err := RequestPort(ip, "tcp", 0); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if newPort == port {
|
||||
t.Fatalf("Acquire(0) allocated the same port twice: %d", port)
|
||||
}
|
||||
|
||||
if _, err := RequestPort(ip, "tcp", 80); err == nil {
|
||||
t.Fatalf("Acquiring a port already in use should return an error")
|
||||
}
|
||||
if _, err := RequestPort(ip2, "tcp", 80); err != nil {
|
||||
t.Fatalf("It should be possible to allocate the same port on a different interface")
|
||||
}
|
||||
if _, err := RequestPort(ip2, "tcp", 80); err == nil {
|
||||
t.Fatalf("Acquiring a port already in use should return an error")
|
||||
}
|
||||
if err := ReleasePort(ip, "tcp", 80); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := RequestPort(ip, "tcp", 80); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
port, err = RequestPort(ip, "tcp", 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
port2, err := RequestPort(ip, "tcp", port+1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
port3, err := RequestPort(ip, "tcp", 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if port3 == port2 {
|
||||
t.Fatal("Requesting a dynamic port should never allocate a used port")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNoDuplicateBPR(t *testing.T) {
|
||||
defer reset()
|
||||
|
||||
if port, err := RequestPort(defaultIP, "tcp", BeginPortRange); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if port != BeginPortRange {
|
||||
t.Fatalf("Expected port %d got %d", BeginPortRange, port)
|
||||
}
|
||||
|
||||
if port, err := RequestPort(defaultIP, "tcp", 0); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if port == BeginPortRange {
|
||||
t.Fatalf("Acquire(0) allocated the same port twice: %d", port)
|
||||
}
|
||||
}
|
176
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/portmapper/mapper.go
generated
vendored
Normal file
176
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/portmapper/mapper.go
generated
vendored
Normal file
|
@ -0,0 +1,176 @@
|
|||
package portmapper
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"sync"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/daemon/networkdriver/portallocator"
|
||||
"github.com/docker/docker/pkg/iptables"
|
||||
)
|
||||
|
||||
type mapping struct {
|
||||
proto string
|
||||
userlandProxy UserlandProxy
|
||||
host net.Addr
|
||||
container net.Addr
|
||||
}
|
||||
|
||||
var (
|
||||
chain *iptables.Chain
|
||||
lock sync.Mutex
|
||||
|
||||
// udp:ip:port
|
||||
currentMappings = make(map[string]*mapping)
|
||||
|
||||
NewProxy = NewProxyCommand
|
||||
)
|
||||
|
||||
var (
|
||||
ErrUnknownBackendAddressType = errors.New("unknown container address type not supported")
|
||||
ErrPortMappedForIP = errors.New("port is already mapped to ip")
|
||||
ErrPortNotMapped = errors.New("port is not mapped")
|
||||
)
|
||||
|
||||
func SetIptablesChain(c *iptables.Chain) {
|
||||
chain = c
|
||||
}
|
||||
|
||||
func Map(container net.Addr, hostIP net.IP, hostPort int) (host net.Addr, err error) {
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
|
||||
var (
|
||||
m *mapping
|
||||
proto string
|
||||
allocatedHostPort int
|
||||
proxy UserlandProxy
|
||||
)
|
||||
|
||||
switch container.(type) {
|
||||
case *net.TCPAddr:
|
||||
proto = "tcp"
|
||||
if allocatedHostPort, err = portallocator.RequestPort(hostIP, proto, hostPort); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
m = &mapping{
|
||||
proto: proto,
|
||||
host: &net.TCPAddr{IP: hostIP, Port: allocatedHostPort},
|
||||
container: container,
|
||||
}
|
||||
|
||||
proxy = NewProxy(proto, hostIP, allocatedHostPort, container.(*net.TCPAddr).IP, container.(*net.TCPAddr).Port)
|
||||
case *net.UDPAddr:
|
||||
proto = "udp"
|
||||
if allocatedHostPort, err = portallocator.RequestPort(hostIP, proto, hostPort); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
m = &mapping{
|
||||
proto: proto,
|
||||
host: &net.UDPAddr{IP: hostIP, Port: allocatedHostPort},
|
||||
container: container,
|
||||
}
|
||||
|
||||
proxy = NewProxy(proto, hostIP, allocatedHostPort, container.(*net.UDPAddr).IP, container.(*net.UDPAddr).Port)
|
||||
default:
|
||||
return nil, ErrUnknownBackendAddressType
|
||||
}
|
||||
|
||||
// release the allocated port on any further error during return.
|
||||
defer func() {
|
||||
if err != nil {
|
||||
portallocator.ReleasePort(hostIP, proto, allocatedHostPort)
|
||||
}
|
||||
}()
|
||||
|
||||
key := getKey(m.host)
|
||||
if _, exists := currentMappings[key]; exists {
|
||||
return nil, ErrPortMappedForIP
|
||||
}
|
||||
|
||||
containerIP, containerPort := getIPAndPort(m.container)
|
||||
if err := forward(iptables.Append, m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cleanup := func() error {
|
||||
// need to undo the iptables rules before we return
|
||||
proxy.Stop()
|
||||
forward(iptables.Delete, m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort)
|
||||
if err := portallocator.ReleasePort(hostIP, m.proto, allocatedHostPort); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := proxy.Start(); err != nil {
|
||||
if err := cleanup(); err != nil {
|
||||
return nil, fmt.Errorf("Error during port allocation cleanup: %v", err)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
m.userlandProxy = proxy
|
||||
currentMappings[key] = m
|
||||
return m.host, nil
|
||||
}
|
||||
|
||||
func Unmap(host net.Addr) error {
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
|
||||
key := getKey(host)
|
||||
data, exists := currentMappings[key]
|
||||
if !exists {
|
||||
return ErrPortNotMapped
|
||||
}
|
||||
|
||||
data.userlandProxy.Stop()
|
||||
|
||||
delete(currentMappings, key)
|
||||
|
||||
containerIP, containerPort := getIPAndPort(data.container)
|
||||
hostIP, hostPort := getIPAndPort(data.host)
|
||||
if err := forward(iptables.Delete, data.proto, hostIP, hostPort, containerIP.String(), containerPort); err != nil {
|
||||
log.Errorf("Error on iptables delete: %s", err)
|
||||
}
|
||||
|
||||
switch a := host.(type) {
|
||||
case *net.TCPAddr:
|
||||
return portallocator.ReleasePort(a.IP, "tcp", a.Port)
|
||||
case *net.UDPAddr:
|
||||
return portallocator.ReleasePort(a.IP, "udp", a.Port)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getKey(a net.Addr) string {
|
||||
switch t := a.(type) {
|
||||
case *net.TCPAddr:
|
||||
return fmt.Sprintf("%s:%d/%s", t.IP.String(), t.Port, "tcp")
|
||||
case *net.UDPAddr:
|
||||
return fmt.Sprintf("%s:%d/%s", t.IP.String(), t.Port, "udp")
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func getIPAndPort(a net.Addr) (net.IP, int) {
|
||||
switch t := a.(type) {
|
||||
case *net.TCPAddr:
|
||||
return t.IP, t.Port
|
||||
case *net.UDPAddr:
|
||||
return t.IP, t.Port
|
||||
}
|
||||
return nil, 0
|
||||
}
|
||||
|
||||
func forward(action iptables.Action, proto string, sourceIP net.IP, sourcePort int, containerIP string, containerPort int) error {
|
||||
if chain == nil {
|
||||
return nil
|
||||
}
|
||||
return chain.Forward(action, sourceIP, sourcePort, proto, containerIP, containerPort)
|
||||
}
|
152
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/portmapper/mapper_test.go
generated
vendored
Normal file
152
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/portmapper/mapper_test.go
generated
vendored
Normal file
|
@ -0,0 +1,152 @@
|
|||
package portmapper
|
||||
|
||||
import (
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/daemon/networkdriver/portallocator"
|
||||
"github.com/docker/docker/pkg/iptables"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// override this func to mock out the proxy server
|
||||
NewProxy = NewMockProxyCommand
|
||||
}
|
||||
|
||||
func reset() {
|
||||
chain = nil
|
||||
currentMappings = make(map[string]*mapping)
|
||||
}
|
||||
|
||||
func TestSetIptablesChain(t *testing.T) {
|
||||
defer reset()
|
||||
|
||||
c := &iptables.Chain{
|
||||
Name: "TEST",
|
||||
Bridge: "192.168.1.1",
|
||||
}
|
||||
|
||||
if chain != nil {
|
||||
t.Fatal("chain should be nil at init")
|
||||
}
|
||||
|
||||
SetIptablesChain(c)
|
||||
if chain == nil {
|
||||
t.Fatal("chain should not be nil after set")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMapPorts(t *testing.T) {
|
||||
dstIp1 := net.ParseIP("192.168.0.1")
|
||||
dstIp2 := net.ParseIP("192.168.0.2")
|
||||
dstAddr1 := &net.TCPAddr{IP: dstIp1, Port: 80}
|
||||
dstAddr2 := &net.TCPAddr{IP: dstIp2, Port: 80}
|
||||
|
||||
srcAddr1 := &net.TCPAddr{Port: 1080, IP: net.ParseIP("172.16.0.1")}
|
||||
srcAddr2 := &net.TCPAddr{Port: 1080, IP: net.ParseIP("172.16.0.2")}
|
||||
|
||||
addrEqual := func(addr1, addr2 net.Addr) bool {
|
||||
return (addr1.Network() == addr2.Network()) && (addr1.String() == addr2.String())
|
||||
}
|
||||
|
||||
if host, err := Map(srcAddr1, dstIp1, 80); err != nil {
|
||||
t.Fatalf("Failed to allocate port: %s", err)
|
||||
} else if !addrEqual(dstAddr1, host) {
|
||||
t.Fatalf("Incorrect mapping result: expected %s:%s, got %s:%s",
|
||||
dstAddr1.String(), dstAddr1.Network(), host.String(), host.Network())
|
||||
}
|
||||
|
||||
if _, err := Map(srcAddr1, dstIp1, 80); err == nil {
|
||||
t.Fatalf("Port is in use - mapping should have failed")
|
||||
}
|
||||
|
||||
if _, err := Map(srcAddr2, dstIp1, 80); err == nil {
|
||||
t.Fatalf("Port is in use - mapping should have failed")
|
||||
}
|
||||
|
||||
if _, err := Map(srcAddr2, dstIp2, 80); err != nil {
|
||||
t.Fatalf("Failed to allocate port: %s", err)
|
||||
}
|
||||
|
||||
if Unmap(dstAddr1) != nil {
|
||||
t.Fatalf("Failed to release port")
|
||||
}
|
||||
|
||||
if Unmap(dstAddr2) != nil {
|
||||
t.Fatalf("Failed to release port")
|
||||
}
|
||||
|
||||
if Unmap(dstAddr2) == nil {
|
||||
t.Fatalf("Port already released, but no error reported")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetUDPKey(t *testing.T) {
|
||||
addr := &net.UDPAddr{IP: net.ParseIP("192.168.1.5"), Port: 53}
|
||||
|
||||
key := getKey(addr)
|
||||
|
||||
if expected := "192.168.1.5:53/udp"; key != expected {
|
||||
t.Fatalf("expected key %s got %s", expected, key)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetTCPKey(t *testing.T) {
|
||||
addr := &net.TCPAddr{IP: net.ParseIP("192.168.1.5"), Port: 80}
|
||||
|
||||
key := getKey(addr)
|
||||
|
||||
if expected := "192.168.1.5:80/tcp"; key != expected {
|
||||
t.Fatalf("expected key %s got %s", expected, key)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetUDPIPAndPort(t *testing.T) {
|
||||
addr := &net.UDPAddr{IP: net.ParseIP("192.168.1.5"), Port: 53}
|
||||
|
||||
ip, port := getIPAndPort(addr)
|
||||
if expected := "192.168.1.5"; ip.String() != expected {
|
||||
t.Fatalf("expected ip %s got %s", expected, ip)
|
||||
}
|
||||
|
||||
if ep := 53; port != ep {
|
||||
t.Fatalf("expected port %d got %d", ep, port)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMapAllPortsSingleInterface(t *testing.T) {
|
||||
dstIp1 := net.ParseIP("0.0.0.0")
|
||||
srcAddr1 := &net.TCPAddr{Port: 1080, IP: net.ParseIP("172.16.0.1")}
|
||||
|
||||
hosts := []net.Addr{}
|
||||
var host net.Addr
|
||||
var err error
|
||||
|
||||
defer func() {
|
||||
for _, val := range hosts {
|
||||
Unmap(val)
|
||||
}
|
||||
}()
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
for i := portallocator.BeginPortRange; i < portallocator.EndPortRange; i++ {
|
||||
if host, err = Map(srcAddr1, dstIp1, 0); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
hosts = append(hosts, host)
|
||||
}
|
||||
|
||||
if _, err := Map(srcAddr1, dstIp1, portallocator.BeginPortRange); err == nil {
|
||||
t.Fatalf("Port %d should be bound but is not", portallocator.BeginPortRange)
|
||||
}
|
||||
|
||||
for _, val := range hosts {
|
||||
if err := Unmap(val); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
hosts = []net.Addr{}
|
||||
}
|
||||
}
|
18
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/portmapper/mock_proxy.go
generated
vendored
Normal file
18
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/portmapper/mock_proxy.go
generated
vendored
Normal file
|
@ -0,0 +1,18 @@
|
|||
package portmapper
|
||||
|
||||
import "net"
|
||||
|
||||
func NewMockProxyCommand(proto string, hostIP net.IP, hostPort int, containerIP net.IP, containerPort int) UserlandProxy {
|
||||
return &mockProxyCommand{}
|
||||
}
|
||||
|
||||
type mockProxyCommand struct {
|
||||
}
|
||||
|
||||
func (p *mockProxyCommand) Start() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *mockProxyCommand) Stop() error {
|
||||
return nil
|
||||
}
|
161
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/portmapper/proxy.go
generated
vendored
Normal file
161
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/portmapper/proxy.go
generated
vendored
Normal file
|
@ -0,0 +1,161 @@
|
|||
package portmapper
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
"strconv"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/pkg/proxy"
|
||||
"github.com/docker/docker/pkg/reexec"
|
||||
)
|
||||
|
||||
const userlandProxyCommandName = "docker-proxy"
|
||||
|
||||
func init() {
|
||||
reexec.Register(userlandProxyCommandName, execProxy)
|
||||
}
|
||||
|
||||
type UserlandProxy interface {
|
||||
Start() error
|
||||
Stop() error
|
||||
}
|
||||
|
||||
// proxyCommand wraps an exec.Cmd to run the userland TCP and UDP
|
||||
// proxies as separate processes.
|
||||
type proxyCommand struct {
|
||||
cmd *exec.Cmd
|
||||
}
|
||||
|
||||
// execProxy is the reexec function that is registered to start the userland proxies
|
||||
func execProxy() {
|
||||
f := os.NewFile(3, "signal-parent")
|
||||
host, container := parseHostContainerAddrs()
|
||||
|
||||
p, err := proxy.NewProxy(host, container)
|
||||
if err != nil {
|
||||
fmt.Fprintf(f, "1\n%s", err)
|
||||
f.Close()
|
||||
os.Exit(1)
|
||||
}
|
||||
go handleStopSignals(p)
|
||||
fmt.Fprint(f, "0\n")
|
||||
f.Close()
|
||||
|
||||
// Run will block until the proxy stops
|
||||
p.Run()
|
||||
}
|
||||
|
||||
// parseHostContainerAddrs parses the flags passed on reexec to create the TCP or UDP
|
||||
// net.Addrs to map the host and container ports
|
||||
func parseHostContainerAddrs() (host net.Addr, container net.Addr) {
|
||||
var (
|
||||
proto = flag.String("proto", "tcp", "proxy protocol")
|
||||
hostIP = flag.String("host-ip", "", "host ip")
|
||||
hostPort = flag.Int("host-port", -1, "host port")
|
||||
containerIP = flag.String("container-ip", "", "container ip")
|
||||
containerPort = flag.Int("container-port", -1, "container port")
|
||||
)
|
||||
|
||||
flag.Parse()
|
||||
|
||||
switch *proto {
|
||||
case "tcp":
|
||||
host = &net.TCPAddr{IP: net.ParseIP(*hostIP), Port: *hostPort}
|
||||
container = &net.TCPAddr{IP: net.ParseIP(*containerIP), Port: *containerPort}
|
||||
case "udp":
|
||||
host = &net.UDPAddr{IP: net.ParseIP(*hostIP), Port: *hostPort}
|
||||
container = &net.UDPAddr{IP: net.ParseIP(*containerIP), Port: *containerPort}
|
||||
default:
|
||||
log.Fatalf("unsupported protocol %s", *proto)
|
||||
}
|
||||
|
||||
return host, container
|
||||
}
|
||||
|
||||
func handleStopSignals(p proxy.Proxy) {
|
||||
s := make(chan os.Signal, 10)
|
||||
signal.Notify(s, os.Interrupt, syscall.SIGTERM, syscall.SIGSTOP)
|
||||
|
||||
for _ = range s {
|
||||
p.Close()
|
||||
|
||||
os.Exit(0)
|
||||
}
|
||||
}
|
||||
|
||||
func NewProxyCommand(proto string, hostIP net.IP, hostPort int, containerIP net.IP, containerPort int) UserlandProxy {
|
||||
args := []string{
|
||||
userlandProxyCommandName,
|
||||
"-proto", proto,
|
||||
"-host-ip", hostIP.String(),
|
||||
"-host-port", strconv.Itoa(hostPort),
|
||||
"-container-ip", containerIP.String(),
|
||||
"-container-port", strconv.Itoa(containerPort),
|
||||
}
|
||||
|
||||
return &proxyCommand{
|
||||
cmd: &exec.Cmd{
|
||||
Path: reexec.Self(),
|
||||
Args: args,
|
||||
SysProcAttr: &syscall.SysProcAttr{
|
||||
Pdeathsig: syscall.SIGTERM, // send a sigterm to the proxy if the daemon process dies
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (p *proxyCommand) Start() error {
|
||||
r, w, err := os.Pipe()
|
||||
if err != nil {
|
||||
return fmt.Errorf("proxy unable to open os.Pipe %s", err)
|
||||
}
|
||||
defer r.Close()
|
||||
p.cmd.ExtraFiles = []*os.File{w}
|
||||
if err := p.cmd.Start(); err != nil {
|
||||
return err
|
||||
}
|
||||
w.Close()
|
||||
|
||||
errchan := make(chan error, 1)
|
||||
go func() {
|
||||
buf := make([]byte, 2)
|
||||
r.Read(buf)
|
||||
|
||||
if string(buf) != "0\n" {
|
||||
errStr, err := ioutil.ReadAll(r)
|
||||
if err != nil {
|
||||
errchan <- fmt.Errorf("Error reading exit status from userland proxy: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
errchan <- fmt.Errorf("Error starting userland proxy: %s", errStr)
|
||||
return
|
||||
}
|
||||
errchan <- nil
|
||||
}()
|
||||
|
||||
select {
|
||||
case err := <-errchan:
|
||||
return err
|
||||
case <-time.After(16 * time.Second):
|
||||
return fmt.Errorf("Timed out proxy starting the userland proxy")
|
||||
}
|
||||
}
|
||||
|
||||
func (p *proxyCommand) Stop() error {
|
||||
if p.cmd.Process != nil {
|
||||
if err := p.cmd.Process.Signal(os.Interrupt); err != nil {
|
||||
return err
|
||||
}
|
||||
return p.cmd.Wait()
|
||||
}
|
||||
return nil
|
||||
}
|
118
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/utils.go
generated
vendored
Normal file
118
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/utils.go
generated
vendored
Normal file
|
@ -0,0 +1,118 @@
|
|||
package networkdriver
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/docker/libcontainer/netlink"
|
||||
)
|
||||
|
||||
var (
|
||||
networkGetRoutesFct = netlink.NetworkGetRoutes
|
||||
ErrNoDefaultRoute = errors.New("no default route")
|
||||
)
|
||||
|
||||
func CheckNameserverOverlaps(nameservers []string, toCheck *net.IPNet) error {
|
||||
if len(nameservers) > 0 {
|
||||
for _, ns := range nameservers {
|
||||
_, nsNetwork, err := net.ParseCIDR(ns)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if NetworkOverlaps(toCheck, nsNetwork) {
|
||||
return ErrNetworkOverlapsWithNameservers
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func CheckRouteOverlaps(toCheck *net.IPNet) error {
|
||||
networks, err := networkGetRoutesFct()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, network := range networks {
|
||||
if network.IPNet != nil && NetworkOverlaps(toCheck, network.IPNet) {
|
||||
return ErrNetworkOverlaps
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Detects overlap between one IPNet and another
|
||||
func NetworkOverlaps(netX *net.IPNet, netY *net.IPNet) bool {
|
||||
if len(netX.IP) == len(netY.IP) {
|
||||
if firstIP, _ := NetworkRange(netX); netY.Contains(firstIP) {
|
||||
return true
|
||||
}
|
||||
if firstIP, _ := NetworkRange(netY); netX.Contains(firstIP) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Calculates the first and last IP addresses in an IPNet
|
||||
func NetworkRange(network *net.IPNet) (net.IP, net.IP) {
|
||||
var netIP net.IP
|
||||
if network.IP.To4() != nil {
|
||||
netIP = network.IP.To4()
|
||||
} else if network.IP.To16() != nil {
|
||||
netIP = network.IP.To16()
|
||||
} else {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
lastIP := make([]byte, len(netIP), len(netIP))
|
||||
|
||||
for i := 0; i < len(netIP); i++ {
|
||||
lastIP[i] = netIP[i] | ^network.Mask[i]
|
||||
}
|
||||
return netIP.Mask(network.Mask), net.IP(lastIP)
|
||||
}
|
||||
|
||||
// Return the first IPv4 address and slice of IPv6 addresses for the specified network interface
|
||||
func GetIfaceAddr(name string) (net.Addr, []net.Addr, error) {
|
||||
iface, err := net.InterfaceByName(name)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
addrs, err := iface.Addrs()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
var addrs4 []net.Addr
|
||||
var addrs6 []net.Addr
|
||||
for _, addr := range addrs {
|
||||
ip := (addr.(*net.IPNet)).IP
|
||||
if ip4 := ip.To4(); ip4 != nil {
|
||||
addrs4 = append(addrs4, addr)
|
||||
} else if ip6 := ip.To16(); len(ip6) == net.IPv6len {
|
||||
addrs6 = append(addrs6, addr)
|
||||
}
|
||||
}
|
||||
switch {
|
||||
case len(addrs4) == 0:
|
||||
return nil, nil, fmt.Errorf("Interface %v has no IPv4 addresses", name)
|
||||
case len(addrs4) > 1:
|
||||
fmt.Printf("Interface %v has more than 1 IPv4 address. Defaulting to using %v\n",
|
||||
name, (addrs4[0].(*net.IPNet)).IP)
|
||||
}
|
||||
return addrs4[0], addrs6, nil
|
||||
}
|
||||
|
||||
func GetDefaultRouteIface() (*net.Interface, error) {
|
||||
rs, err := networkGetRoutesFct()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to get routes: %v", err)
|
||||
}
|
||||
for _, r := range rs {
|
||||
if r.Default {
|
||||
return r.Iface, nil
|
||||
}
|
||||
}
|
||||
return nil, ErrNoDefaultRoute
|
||||
}
|
93
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/parsers/kernel/kernel.go
generated
vendored
Normal file
93
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/parsers/kernel/kernel.go
generated
vendored
Normal file
|
@ -0,0 +1,93 @@
|
|||
package kernel
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type KernelVersionInfo struct {
|
||||
Kernel int
|
||||
Major int
|
||||
Minor int
|
||||
Flavor string
|
||||
}
|
||||
|
||||
func (k *KernelVersionInfo) String() string {
|
||||
return fmt.Sprintf("%d.%d.%d%s", k.Kernel, k.Major, k.Minor, k.Flavor)
|
||||
}
|
||||
|
||||
// Compare two KernelVersionInfo struct.
|
||||
// Returns -1 if a < b, 0 if a == b, 1 it a > b
|
||||
func CompareKernelVersion(a, b *KernelVersionInfo) int {
|
||||
if a.Kernel < b.Kernel {
|
||||
return -1
|
||||
} else if a.Kernel > b.Kernel {
|
||||
return 1
|
||||
}
|
||||
|
||||
if a.Major < b.Major {
|
||||
return -1
|
||||
} else if a.Major > b.Major {
|
||||
return 1
|
||||
}
|
||||
|
||||
if a.Minor < b.Minor {
|
||||
return -1
|
||||
} else if a.Minor > b.Minor {
|
||||
return 1
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func GetKernelVersion() (*KernelVersionInfo, error) {
|
||||
var (
|
||||
err error
|
||||
)
|
||||
|
||||
uts, err := uname()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
release := make([]byte, len(uts.Release))
|
||||
|
||||
i := 0
|
||||
for _, c := range uts.Release {
|
||||
release[i] = byte(c)
|
||||
i++
|
||||
}
|
||||
|
||||
// Remove the \x00 from the release for Atoi to parse correctly
|
||||
release = release[:bytes.IndexByte(release, 0)]
|
||||
|
||||
return ParseRelease(string(release))
|
||||
}
|
||||
|
||||
func ParseRelease(release string) (*KernelVersionInfo, error) {
|
||||
var (
|
||||
kernel, major, minor, parsed int
|
||||
flavor, partial string
|
||||
)
|
||||
|
||||
// Ignore error from Sscanf to allow an empty flavor. Instead, just
|
||||
// make sure we got all the version numbers.
|
||||
parsed, _ = fmt.Sscanf(release, "%d.%d%s", &kernel, &major, &partial)
|
||||
if parsed < 2 {
|
||||
return nil, errors.New("Can't parse kernel version " + release)
|
||||
}
|
||||
|
||||
// sometimes we have 3.12.25-gentoo, but sometimes we just have 3.12-1-amd64
|
||||
parsed, _ = fmt.Sscanf(partial, ".%d%s", &minor, &flavor)
|
||||
if parsed < 1 {
|
||||
flavor = partial
|
||||
}
|
||||
|
||||
return &KernelVersionInfo{
|
||||
Kernel: kernel,
|
||||
Major: major,
|
||||
Minor: minor,
|
||||
Flavor: flavor,
|
||||
}, nil
|
||||
}
|
61
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/parsers/kernel/kernel_test.go
generated
vendored
Normal file
61
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/parsers/kernel/kernel_test.go
generated
vendored
Normal file
|
@ -0,0 +1,61 @@
|
|||
package kernel
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func assertParseRelease(t *testing.T, release string, b *KernelVersionInfo, result int) {
|
||||
var (
|
||||
a *KernelVersionInfo
|
||||
)
|
||||
a, _ = ParseRelease(release)
|
||||
|
||||
if r := CompareKernelVersion(a, b); r != result {
|
||||
t.Fatalf("Unexpected kernel version comparison result. Found %d, expected %d", r, result)
|
||||
}
|
||||
if a.Flavor != b.Flavor {
|
||||
t.Fatalf("Unexpected parsed kernel flavor. Found %s, expected %s", a.Flavor, b.Flavor)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseRelease(t *testing.T) {
|
||||
assertParseRelease(t, "3.8.0", &KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0}, 0)
|
||||
assertParseRelease(t, "3.4.54.longterm-1", &KernelVersionInfo{Kernel: 3, Major: 4, Minor: 54, Flavor: ".longterm-1"}, 0)
|
||||
assertParseRelease(t, "3.4.54.longterm-1", &KernelVersionInfo{Kernel: 3, Major: 4, Minor: 54, Flavor: ".longterm-1"}, 0)
|
||||
assertParseRelease(t, "3.8.0-19-generic", &KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0, Flavor: "-19-generic"}, 0)
|
||||
assertParseRelease(t, "3.12.8tag", &KernelVersionInfo{Kernel: 3, Major: 12, Minor: 8, Flavor: "tag"}, 0)
|
||||
assertParseRelease(t, "3.12-1-amd64", &KernelVersionInfo{Kernel: 3, Major: 12, Minor: 0, Flavor: "-1-amd64"}, 0)
|
||||
}
|
||||
|
||||
func assertKernelVersion(t *testing.T, a, b *KernelVersionInfo, result int) {
|
||||
if r := CompareKernelVersion(a, b); r != result {
|
||||
t.Fatalf("Unexpected kernel version comparison result. Found %d, expected %d", r, result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCompareKernelVersion(t *testing.T) {
|
||||
assertKernelVersion(t,
|
||||
&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0},
|
||||
&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0},
|
||||
0)
|
||||
assertKernelVersion(t,
|
||||
&KernelVersionInfo{Kernel: 2, Major: 6, Minor: 0},
|
||||
&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0},
|
||||
-1)
|
||||
assertKernelVersion(t,
|
||||
&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0},
|
||||
&KernelVersionInfo{Kernel: 2, Major: 6, Minor: 0},
|
||||
1)
|
||||
assertKernelVersion(t,
|
||||
&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0},
|
||||
&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0},
|
||||
0)
|
||||
assertKernelVersion(t,
|
||||
&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 5},
|
||||
&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0},
|
||||
1)
|
||||
assertKernelVersion(t,
|
||||
&KernelVersionInfo{Kernel: 3, Major: 0, Minor: 20},
|
||||
&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0},
|
||||
-1)
|
||||
}
|
16
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/parsers/kernel/uname_linux.go
generated
vendored
Normal file
16
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/parsers/kernel/uname_linux.go
generated
vendored
Normal file
|
@ -0,0 +1,16 @@
|
|||
package kernel
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
type Utsname syscall.Utsname
|
||||
|
||||
func uname() (*syscall.Utsname, error) {
|
||||
uts := &syscall.Utsname{}
|
||||
|
||||
if err := syscall.Uname(uts); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return uts, nil
|
||||
}
|
15
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/parsers/kernel/uname_unsupported.go
generated
vendored
Normal file
15
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/parsers/kernel/uname_unsupported.go
generated
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
// +build !linux
|
||||
|
||||
package kernel
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
type Utsname struct {
|
||||
Release [65]byte
|
||||
}
|
||||
|
||||
func uname() (*Utsname, error) {
|
||||
return nil, errors.New("Kernel version detection is available only on linux")
|
||||
}
|
1
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/reexec/MAINTAINERS
generated
vendored
Normal file
1
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/reexec/MAINTAINERS
generated
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
Michael Crosby <michael@docker.com> (@crosbymichael)
|
5
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/reexec/README.md
generated
vendored
Normal file
5
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/reexec/README.md
generated
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
## reexec
|
||||
|
||||
The `reexec` package facilitates the busybox style reexec of the docker binary that we require because
|
||||
of the forking limitations of using Go. Handlers can be registered with a name and the argv 0 of
|
||||
the exec of the binary will be used to find and execute custom init paths.
|
18
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/reexec/command_linux.go
generated
vendored
Normal file
18
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/reexec/command_linux.go
generated
vendored
Normal file
|
@ -0,0 +1,18 @@
|
|||
// +build linux
|
||||
|
||||
package reexec
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func Command(args ...string) *exec.Cmd {
|
||||
return &exec.Cmd{
|
||||
Path: Self(),
|
||||
Args: args,
|
||||
SysProcAttr: &syscall.SysProcAttr{
|
||||
Pdeathsig: syscall.SIGTERM,
|
||||
},
|
||||
}
|
||||
}
|
11
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/reexec/command_unsupported.go
generated
vendored
Normal file
11
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/reexec/command_unsupported.go
generated
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
// +build !linux
|
||||
|
||||
package reexec
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
func Command(args ...string) *exec.Cmd {
|
||||
return nil
|
||||
}
|
42
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/reexec/reexec.go
generated
vendored
Normal file
42
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/reexec/reexec.go
generated
vendored
Normal file
|
@ -0,0 +1,42 @@
|
|||
package reexec
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
var registeredInitializers = make(map[string]func())
|
||||
|
||||
// Register adds an initialization func under the specified name
|
||||
func Register(name string, initializer func()) {
|
||||
if _, exists := registeredInitializers[name]; exists {
|
||||
panic(fmt.Sprintf("reexec func already registred under name %q", name))
|
||||
}
|
||||
|
||||
registeredInitializers[name] = initializer
|
||||
}
|
||||
|
||||
// Init is called as the first part of the exec process and returns true if an
|
||||
// initialization function was called.
|
||||
func Init() bool {
|
||||
initializer, exists := registeredInitializers[os.Args[0]]
|
||||
if exists {
|
||||
initializer()
|
||||
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Self returns the path to the current processes binary
|
||||
func Self() string {
|
||||
name := os.Args[0]
|
||||
if filepath.Base(name) == name {
|
||||
if lp, err := exec.LookPath(name); err == nil {
|
||||
name = lp
|
||||
}
|
||||
}
|
||||
return name
|
||||
}
|
2
libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/MAINTAINERS
generated
vendored
Normal file
2
libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/MAINTAINERS
generated
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
Michael Crosby <michael@crosbymichael.com> (@crosbymichael)
|
||||
Guillaume J. Charmes <guillaume@docker.com> (@creack)
|
31
libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink.go
generated
vendored
Normal file
31
libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink.go
generated
vendored
Normal file
|
@ -0,0 +1,31 @@
|
|||
// Packet netlink provide access to low level Netlink sockets and messages.
|
||||
//
|
||||
// Actual implementations are in:
|
||||
// netlink_linux.go
|
||||
// netlink_darwin.go
|
||||
package netlink
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrWrongSockType = errors.New("Wrong socket type")
|
||||
ErrShortResponse = errors.New("Got short response from netlink")
|
||||
ErrInterfaceExists = errors.New("Network interface already exists")
|
||||
)
|
||||
|
||||
// A Route is a subnet associated with the interface to reach it.
|
||||
type Route struct {
|
||||
*net.IPNet
|
||||
Iface *net.Interface
|
||||
Default bool
|
||||
}
|
||||
|
||||
// An IfAddr defines IP network settings for a given network interface
|
||||
type IfAddr struct {
|
||||
Iface *net.Interface
|
||||
IP net.IP
|
||||
IPNet *net.IPNet
|
||||
}
|
1307
libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_linux.go
generated
vendored
Normal file
1307
libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_linux.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
5
libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_linux_arm.go
generated
vendored
Normal file
5
libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_linux_arm.go
generated
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
package netlink
|
||||
|
||||
func ifrDataByte(b byte) uint8 {
|
||||
return uint8(b)
|
||||
}
|
7
libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_linux_notarm.go
generated
vendored
Normal file
7
libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_linux_notarm.go
generated
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
// +build !arm
|
||||
|
||||
package netlink
|
||||
|
||||
func ifrDataByte(b byte) int8 {
|
||||
return int8(b)
|
||||
}
|
408
libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_linux_test.go
generated
vendored
Normal file
408
libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_linux_test.go
generated
vendored
Normal file
|
@ -0,0 +1,408 @@
|
|||
package netlink
|
||||
|
||||
import (
|
||||
"net"
|
||||
"strings"
|
||||
"syscall"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type testLink struct {
|
||||
name string
|
||||
linkType string
|
||||
}
|
||||
|
||||
func addLink(t *testing.T, name string, linkType string) {
|
||||
if err := NetworkLinkAdd(name, linkType); err != nil {
|
||||
t.Fatalf("Unable to create %s link: %s", name, err)
|
||||
}
|
||||
}
|
||||
|
||||
func readLink(t *testing.T, name string) *net.Interface {
|
||||
iface, err := net.InterfaceByName(name)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not find %s interface: %s", name, err)
|
||||
}
|
||||
|
||||
return iface
|
||||
}
|
||||
|
||||
func deleteLink(t *testing.T, name string) {
|
||||
if err := NetworkLinkDel(name); err != nil {
|
||||
t.Fatalf("Unable to delete %s link: %s", name, err)
|
||||
}
|
||||
}
|
||||
|
||||
func upLink(t *testing.T, name string) {
|
||||
iface := readLink(t, name)
|
||||
if err := NetworkLinkUp(iface); err != nil {
|
||||
t.Fatalf("Could not bring UP %#v interface: %s", iface, err)
|
||||
}
|
||||
}
|
||||
|
||||
func downLink(t *testing.T, name string) {
|
||||
iface := readLink(t, name)
|
||||
if err := NetworkLinkDown(iface); err != nil {
|
||||
t.Fatalf("Could not bring DOWN %#v interface: %s", iface, err)
|
||||
}
|
||||
}
|
||||
|
||||
func ipAssigned(iface *net.Interface, ip net.IP) bool {
|
||||
addrs, _ := iface.Addrs()
|
||||
|
||||
for _, addr := range addrs {
|
||||
args := strings.SplitN(addr.String(), "/", 2)
|
||||
if args[0] == ip.String() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func TestNetworkLinkAddDel(t *testing.T) {
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
|
||||
testLinks := []testLink{
|
||||
{"tstEth", "dummy"},
|
||||
{"tstBr", "bridge"},
|
||||
}
|
||||
|
||||
for _, tl := range testLinks {
|
||||
addLink(t, tl.name, tl.linkType)
|
||||
defer deleteLink(t, tl.name)
|
||||
readLink(t, tl.name)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNetworkLinkUpDown(t *testing.T) {
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
|
||||
tl := testLink{name: "tstEth", linkType: "dummy"}
|
||||
|
||||
addLink(t, tl.name, tl.linkType)
|
||||
defer deleteLink(t, tl.name)
|
||||
|
||||
upLink(t, tl.name)
|
||||
ifcAfterUp := readLink(t, tl.name)
|
||||
|
||||
if (ifcAfterUp.Flags & syscall.IFF_UP) != syscall.IFF_UP {
|
||||
t.Fatalf("Could not bring UP %#v initerface", tl)
|
||||
}
|
||||
|
||||
downLink(t, tl.name)
|
||||
ifcAfterDown := readLink(t, tl.name)
|
||||
|
||||
if (ifcAfterDown.Flags & syscall.IFF_UP) == syscall.IFF_UP {
|
||||
t.Fatalf("Could not bring DOWN %#v initerface", tl)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNetworkSetMacAddress(t *testing.T) {
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
|
||||
tl := testLink{name: "tstEth", linkType: "dummy"}
|
||||
macaddr := "22:ce:e0:99:63:6f"
|
||||
|
||||
addLink(t, tl.name, tl.linkType)
|
||||
defer deleteLink(t, tl.name)
|
||||
|
||||
ifcBeforeSet := readLink(t, tl.name)
|
||||
|
||||
if err := NetworkSetMacAddress(ifcBeforeSet, macaddr); err != nil {
|
||||
t.Fatalf("Could not set %s MAC address on %#v interface: %s", macaddr, tl, err)
|
||||
}
|
||||
|
||||
ifcAfterSet := readLink(t, tl.name)
|
||||
|
||||
if ifcAfterSet.HardwareAddr.String() != macaddr {
|
||||
t.Fatalf("Could not set %s MAC address on %#v interface", macaddr, tl)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNetworkSetMTU(t *testing.T) {
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
|
||||
tl := testLink{name: "tstEth", linkType: "dummy"}
|
||||
mtu := 1400
|
||||
|
||||
addLink(t, tl.name, tl.linkType)
|
||||
defer deleteLink(t, tl.name)
|
||||
|
||||
ifcBeforeSet := readLink(t, tl.name)
|
||||
|
||||
if err := NetworkSetMTU(ifcBeforeSet, mtu); err != nil {
|
||||
t.Fatalf("Could not set %d MTU on %#v interface: %s", mtu, tl, err)
|
||||
}
|
||||
|
||||
ifcAfterSet := readLink(t, tl.name)
|
||||
|
||||
if ifcAfterSet.MTU != mtu {
|
||||
t.Fatalf("Could not set %d MTU on %#v interface", mtu, tl)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNetworkSetMasterNoMaster(t *testing.T) {
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
|
||||
master := testLink{"tstBr", "bridge"}
|
||||
slave := testLink{"tstEth", "dummy"}
|
||||
testLinks := []testLink{master, slave}
|
||||
|
||||
for _, tl := range testLinks {
|
||||
addLink(t, tl.name, tl.linkType)
|
||||
defer deleteLink(t, tl.name)
|
||||
upLink(t, tl.name)
|
||||
}
|
||||
|
||||
masterIfc := readLink(t, master.name)
|
||||
slaveIfc := readLink(t, slave.name)
|
||||
if err := NetworkSetMaster(slaveIfc, masterIfc); err != nil {
|
||||
t.Fatalf("Could not set %#v to be the master of %#v: %s", master, slave, err)
|
||||
}
|
||||
|
||||
// Trying to figure out a way to test which will not break on RHEL6.
|
||||
// We could check for existence of /sys/class/net/tstEth/upper_tstBr
|
||||
// which should point to the ../tstBr which is the UPPER device i.e. network bridge
|
||||
|
||||
if err := NetworkSetNoMaster(slaveIfc); err != nil {
|
||||
t.Fatalf("Could not UNset %#v master of %#v: %s", master, slave, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNetworkChangeName(t *testing.T) {
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
|
||||
tl := testLink{"tstEth", "dummy"}
|
||||
newName := "newTst"
|
||||
|
||||
addLink(t, tl.name, tl.linkType)
|
||||
|
||||
linkIfc := readLink(t, tl.name)
|
||||
if err := NetworkChangeName(linkIfc, newName); err != nil {
|
||||
deleteLink(t, tl.name)
|
||||
t.Fatalf("Could not change %#v interface name to %s: %s", tl, newName, err)
|
||||
}
|
||||
|
||||
readLink(t, newName)
|
||||
deleteLink(t, newName)
|
||||
}
|
||||
|
||||
func TestNetworkLinkAddVlan(t *testing.T) {
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
|
||||
tl := struct {
|
||||
name string
|
||||
id uint16
|
||||
}{
|
||||
name: "tstVlan",
|
||||
id: 32,
|
||||
}
|
||||
masterLink := testLink{"tstEth", "dummy"}
|
||||
|
||||
addLink(t, masterLink.name, masterLink.linkType)
|
||||
defer deleteLink(t, masterLink.name)
|
||||
|
||||
if err := NetworkLinkAddVlan(masterLink.name, tl.name, tl.id); err != nil {
|
||||
t.Fatalf("Unable to create %#v VLAN interface: %s", tl, err)
|
||||
}
|
||||
|
||||
readLink(t, tl.name)
|
||||
}
|
||||
|
||||
func TestNetworkLinkAddMacVlan(t *testing.T) {
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
|
||||
tl := struct {
|
||||
name string
|
||||
mode string
|
||||
}{
|
||||
name: "tstVlan",
|
||||
mode: "private",
|
||||
}
|
||||
masterLink := testLink{"tstEth", "dummy"}
|
||||
|
||||
addLink(t, masterLink.name, masterLink.linkType)
|
||||
defer deleteLink(t, masterLink.name)
|
||||
|
||||
if err := NetworkLinkAddMacVlan(masterLink.name, tl.name, tl.mode); err != nil {
|
||||
t.Fatalf("Unable to create %#v MAC VLAN interface: %s", tl, err)
|
||||
}
|
||||
|
||||
readLink(t, tl.name)
|
||||
}
|
||||
|
||||
func TestNetworkLinkAddMacVtap(t *testing.T) {
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
|
||||
tl := struct {
|
||||
name string
|
||||
mode string
|
||||
}{
|
||||
name: "tstVtap",
|
||||
mode: "private",
|
||||
}
|
||||
masterLink := testLink{"tstEth", "dummy"}
|
||||
|
||||
addLink(t, masterLink.name, masterLink.linkType)
|
||||
defer deleteLink(t, masterLink.name)
|
||||
|
||||
if err := NetworkLinkAddMacVtap(masterLink.name, tl.name, tl.mode); err != nil {
|
||||
t.Fatalf("Unable to create %#v MAC VTAP interface: %s", tl, err)
|
||||
}
|
||||
|
||||
readLink(t, tl.name)
|
||||
}
|
||||
|
||||
func TestAddDelNetworkIp(t *testing.T) {
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
|
||||
ifaceName := "lo"
|
||||
ip := net.ParseIP("127.0.1.1")
|
||||
mask := net.IPv4Mask(255, 255, 255, 255)
|
||||
ipNet := &net.IPNet{IP: ip, Mask: mask}
|
||||
|
||||
iface, err := net.InterfaceByName(ifaceName)
|
||||
if err != nil {
|
||||
t.Skip("No 'lo' interface; skipping tests")
|
||||
}
|
||||
|
||||
if err := NetworkLinkAddIp(iface, ip, ipNet); err != nil {
|
||||
t.Fatalf("Could not add IP address %s to interface %#v: %s", ip.String(), iface, err)
|
||||
}
|
||||
|
||||
if !ipAssigned(iface, ip) {
|
||||
t.Fatalf("Could not locate address '%s' in lo address list.", ip.String())
|
||||
}
|
||||
|
||||
if err := NetworkLinkDelIp(iface, ip, ipNet); err != nil {
|
||||
t.Fatalf("Could not delete IP address %s from interface %#v: %s", ip.String(), iface, err)
|
||||
}
|
||||
|
||||
if ipAssigned(iface, ip) {
|
||||
t.Fatalf("Located address '%s' in lo address list after removal.", ip.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddRouteSourceSelection(t *testing.T) {
|
||||
tstIp := "127.1.1.1"
|
||||
tl := testLink{name: "tstEth", linkType: "dummy"}
|
||||
|
||||
addLink(t, tl.name, tl.linkType)
|
||||
defer deleteLink(t, tl.name)
|
||||
|
||||
ip := net.ParseIP(tstIp)
|
||||
mask := net.IPv4Mask(255, 255, 255, 255)
|
||||
ipNet := &net.IPNet{IP: ip, Mask: mask}
|
||||
|
||||
iface, err := net.InterfaceByName(tl.name)
|
||||
if err != nil {
|
||||
t.Fatalf("Lost created link %#v", tl)
|
||||
}
|
||||
|
||||
if err := NetworkLinkAddIp(iface, ip, ipNet); err != nil {
|
||||
t.Fatalf("Could not add IP address %s to interface %#v: %s", ip.String(), iface, err)
|
||||
}
|
||||
|
||||
upLink(t, tl.name)
|
||||
defer downLink(t, tl.name)
|
||||
|
||||
if err := AddRoute("127.0.0.0/8", tstIp, "", tl.name); err != nil {
|
||||
t.Fatalf("Failed to add route with source address")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateVethPair(t *testing.T) {
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
|
||||
var (
|
||||
name1 = "veth1"
|
||||
name2 = "veth2"
|
||||
)
|
||||
|
||||
if err := NetworkCreateVethPair(name1, name2, 0); err != nil {
|
||||
t.Fatalf("Could not create veth pair %s %s: %s", name1, name2, err)
|
||||
}
|
||||
defer NetworkLinkDel(name1)
|
||||
|
||||
readLink(t, name1)
|
||||
readLink(t, name2)
|
||||
}
|
||||
|
||||
//
|
||||
// netlink package tests which do not use RTNETLINK
|
||||
//
|
||||
func TestCreateBridgeWithMac(t *testing.T) {
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
|
||||
name := "testbridge"
|
||||
|
||||
if err := CreateBridge(name, true); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err := net.InterfaceByName(name); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// cleanup and tests
|
||||
|
||||
if err := DeleteBridge(name); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err := net.InterfaceByName(name); err == nil {
|
||||
t.Fatalf("expected error getting interface because %s bridge was deleted", name)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetMacAddress(t *testing.T) {
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
|
||||
name := "testmac"
|
||||
mac := randMacAddr()
|
||||
|
||||
if err := NetworkLinkAdd(name, "bridge"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer NetworkLinkDel(name)
|
||||
|
||||
if err := SetMacAddress(name, mac); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
iface, err := net.InterfaceByName(name)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if iface.HardwareAddr.String() != mac {
|
||||
t.Fatalf("mac address %q does not match %q", iface.HardwareAddr, mac)
|
||||
}
|
||||
}
|
88
libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_unsupported.go
generated
vendored
Normal file
88
libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_unsupported.go
generated
vendored
Normal file
|
@ -0,0 +1,88 @@
|
|||
// +build !linux
|
||||
|
||||
package netlink
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrNotImplemented = errors.New("not implemented")
|
||||
)
|
||||
|
||||
func NetworkGetRoutes() ([]Route, error) {
|
||||
return nil, ErrNotImplemented
|
||||
}
|
||||
|
||||
func NetworkLinkAdd(name string, linkType string) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func NetworkLinkDel(name string) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func NetworkLinkUp(iface *net.Interface) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func NetworkLinkAddIp(iface *net.Interface, ip net.IP, ipNet *net.IPNet) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func NetworkLinkDelIp(iface *net.Interface, ip net.IP, ipNet *net.IPNet) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func AddRoute(destination, source, gateway, device string) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func AddDefaultGw(ip, device string) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func NetworkSetMTU(iface *net.Interface, mtu int) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func NetworkSetTxQueueLen(iface *net.Interface, txQueueLen int) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func NetworkCreateVethPair(name1, name2 string, txQueueLen int) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func NetworkChangeName(iface *net.Interface, newName string) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func NetworkSetNsFd(iface *net.Interface, fd int) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func NetworkSetNsPid(iface *net.Interface, nspid int) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func NetworkSetMaster(iface, master *net.Interface) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func NetworkLinkDown(iface *net.Interface) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func CreateBridge(name string, setMacAddr bool) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func DeleteBridge(name string) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func AddToBridge(iface, master *net.Interface) error {
|
||||
return ErrNotImplemented
|
||||
}
|
3
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/.travis.yml
generated
vendored
Normal file
3
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/.travis.yml
generated
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
language: go
|
||||
install:
|
||||
- go get github.com/vishvananda/netns
|
192
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/LICENSE
generated
vendored
Normal file
192
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,192 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Copyright 2014 Vishvananda Ishaya.
|
||||
Copyright 2014 Docker, Inc.
|
||||
|
||||
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.
|
29
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/Makefile
generated
vendored
Normal file
29
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/Makefile
generated
vendored
Normal file
|
@ -0,0 +1,29 @@
|
|||
DIRS := \
|
||||
. \
|
||||
nl
|
||||
|
||||
DEPS = \
|
||||
github.com/vishvananda/netns
|
||||
|
||||
uniq = $(if $1,$(firstword $1) $(call uniq,$(filter-out $(firstword $1),$1)))
|
||||
testdirs = $(call uniq,$(foreach d,$(1),$(dir $(wildcard $(d)/*_test.go))))
|
||||
goroot = $(addprefix ../../../,$(1))
|
||||
unroot = $(subst ../../../,,$(1))
|
||||
fmt = $(addprefix fmt-,$(1))
|
||||
|
||||
all: fmt
|
||||
|
||||
$(call goroot,$(DEPS)):
|
||||
go get $(call unroot,$@)
|
||||
|
||||
.PHONY: $(call testdirs,$(DIRS))
|
||||
$(call testdirs,$(DIRS)):
|
||||
sudo -E go test -v github.com/vishvananda/netlink/$@
|
||||
|
||||
$(call fmt,$(call testdirs,$(DIRS))):
|
||||
! gofmt -l $(subst fmt-,,$@)/*.go | grep ''
|
||||
|
||||
.PHONY: fmt
|
||||
fmt: $(call fmt,$(call testdirs,$(DIRS)))
|
||||
|
||||
test: fmt $(call goroot,$(DEPS)) $(call testdirs,$(DIRS))
|
83
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/README.md
generated
vendored
Normal file
83
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/README.md
generated
vendored
Normal file
|
@ -0,0 +1,83 @@
|
|||
# netlink - netlink library for go #
|
||||
|
||||
[](https://travis-ci.org/vishvananda/netlink) [](https://godoc.org/github.com/vishvananda/netlink)
|
||||
|
||||
The netlink package provides a simple netlink library for go. Netlink
|
||||
is the interface a user-space program in linux uses to communicate with
|
||||
the kernel. It can be used to add and remove interfaces, set ip addresses
|
||||
and routes, and configure ipsec. Netlink communication requires elevated
|
||||
privileges, so in most cases this code needs to be run as root. Since
|
||||
low-level netlink messages are inscrutable at best, the library attempts
|
||||
to provide an api that is loosely modeled on the CLI provied by iproute2.
|
||||
Actions like `ip link add` will be accomplished via a similarly named
|
||||
function like AddLink(). This library began its life as a fork of the
|
||||
netlink functionality in
|
||||
[docker/libcontainer](https://github.com/docker/libcontainer) but was
|
||||
heavily rewritten to improve testability, performance, and to add new
|
||||
functionality like ipsec xfrm handling.
|
||||
|
||||
## Local Build and Test ##
|
||||
|
||||
You can use go get command:
|
||||
|
||||
go get github.com/vishvananda/netlink
|
||||
|
||||
Testing dependencies:
|
||||
|
||||
go get github.com/vishvananda/netns
|
||||
|
||||
Testing (requires root):
|
||||
|
||||
sudo -E go test github.com/vishvananda/netlink
|
||||
|
||||
## Examples ##
|
||||
|
||||
Add a new bridge and add eth1 into it:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"net"
|
||||
"github.com/vishvananda/netlink"
|
||||
)
|
||||
|
||||
func main() {
|
||||
mybridge := &netlink.Bridge{netlink.LinkAttrs{Name: "foo"}}
|
||||
_ := netlink.LinkAdd(mybridge)
|
||||
eth1, _ := netlink.LinkByName("eth1")
|
||||
netlink.LinkSetMaster(eth1, mybridge)
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Add a new ip address to loopback:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"net"
|
||||
"github.com/vishvananda/netlink"
|
||||
)
|
||||
|
||||
func main() {
|
||||
lo, _ := netlink.LinkByName("lo")
|
||||
addr, _ := netlink.ParseAddr("169.254.169.254/32")
|
||||
netlink.AddrAdd(lo, addr)
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Future Work ##
|
||||
|
||||
Many pieces of netlink are not yet fully supported in the high-level
|
||||
interface. Aspects of virtually all of the high-level objects don't exist.
|
||||
Many of the underlying primitives are there, so its a matter of putting
|
||||
the right fields into the high-level objects and making sure that they
|
||||
are serialized and deserialized correctly in the Add and List methods.
|
||||
|
||||
There are also a few pieces of low level netlink functionality that still
|
||||
need to be implemented. Routing rules are not in place and some of the
|
||||
more advanced link types. Hopefully there is decent structure and testing
|
||||
in place to make these fairly straightforward to add.
|
43
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/addr.go
generated
vendored
Normal file
43
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/addr.go
generated
vendored
Normal file
|
@ -0,0 +1,43 @@
|
|||
package netlink
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Addr represents an IP address from netlink. Netlink ip addresses
|
||||
// include a mask, so it stores the address as a net.IPNet.
|
||||
type Addr struct {
|
||||
*net.IPNet
|
||||
Label string
|
||||
}
|
||||
|
||||
// String returns $ip/$netmask $label
|
||||
func (addr Addr) String() string {
|
||||
return fmt.Sprintf("%s %s", addr.IPNet, addr.Label)
|
||||
}
|
||||
|
||||
// ParseAddr parses the string representation of an address in the
|
||||
// form $ip/$netmask $label. The label portion is optional
|
||||
func ParseAddr(s string) (*Addr, error) {
|
||||
label := ""
|
||||
parts := strings.Split(s, " ")
|
||||
if len(parts) > 1 {
|
||||
s = parts[0]
|
||||
label = parts[1]
|
||||
}
|
||||
m, err := ParseIPNet(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Addr{IPNet: m, Label: label}, nil
|
||||
}
|
||||
|
||||
// Equal returns true if both Addrs have the same net.IPNet value.
|
||||
func (a Addr) Equal(x Addr) bool {
|
||||
sizea, _ := a.Mask.Size()
|
||||
sizeb, _ := x.Mask.Size()
|
||||
// ignore label for comparison
|
||||
return a.IP.Equal(x.IP) && sizea == sizeb
|
||||
}
|
114
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/addr_linux.go
generated
vendored
Normal file
114
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/addr_linux.go
generated
vendored
Normal file
|
@ -0,0 +1,114 @@
|
|||
package netlink
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/vishvananda/netlink/nl"
|
||||
)
|
||||
|
||||
// AddrAdd will add an IP address to a link device.
|
||||
// Equivalent to: `ip addr add $addr dev $link`
|
||||
func AddrAdd(link Link, addr *Addr) error {
|
||||
|
||||
req := nl.NewNetlinkRequest(syscall.RTM_NEWADDR, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
|
||||
return addrHandle(link, addr, req)
|
||||
}
|
||||
|
||||
// AddrDel will delete an IP address from a link device.
|
||||
// Equivalent to: `ip addr del $addr dev $link`
|
||||
func AddrDel(link Link, addr *Addr) error {
|
||||
req := nl.NewNetlinkRequest(syscall.RTM_DELADDR, syscall.NLM_F_ACK)
|
||||
return addrHandle(link, addr, req)
|
||||
}
|
||||
|
||||
func addrHandle(link Link, addr *Addr, req *nl.NetlinkRequest) error {
|
||||
base := link.Attrs()
|
||||
if addr.Label != "" && !strings.HasPrefix(addr.Label, base.Name) {
|
||||
return fmt.Errorf("label must begin with interface name")
|
||||
}
|
||||
ensureIndex(base)
|
||||
|
||||
family := nl.GetIPFamily(addr.IP)
|
||||
|
||||
msg := nl.NewIfAddrmsg(family)
|
||||
msg.Index = uint32(base.Index)
|
||||
prefixlen, _ := addr.Mask.Size()
|
||||
msg.Prefixlen = uint8(prefixlen)
|
||||
req.AddData(msg)
|
||||
|
||||
var addrData []byte
|
||||
if family == FAMILY_V4 {
|
||||
addrData = addr.IP.To4()
|
||||
} else {
|
||||
addrData = addr.IP.To16()
|
||||
}
|
||||
|
||||
localData := nl.NewRtAttr(syscall.IFA_LOCAL, addrData)
|
||||
req.AddData(localData)
|
||||
|
||||
addressData := nl.NewRtAttr(syscall.IFA_ADDRESS, addrData)
|
||||
req.AddData(addressData)
|
||||
|
||||
if addr.Label != "" {
|
||||
labelData := nl.NewRtAttr(syscall.IFA_LABEL, nl.ZeroTerminated(addr.Label))
|
||||
req.AddData(labelData)
|
||||
}
|
||||
|
||||
_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
|
||||
return err
|
||||
}
|
||||
|
||||
// AddrList gets a list of IP addresses in the system.
|
||||
// Equivalent to: `ip addr show`.
|
||||
// The list can be filtered by link and ip family.
|
||||
func AddrList(link Link, family int) ([]Addr, error) {
|
||||
req := nl.NewNetlinkRequest(syscall.RTM_GETADDR, syscall.NLM_F_DUMP)
|
||||
msg := nl.NewIfInfomsg(family)
|
||||
req.AddData(msg)
|
||||
|
||||
msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWADDR)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
index := 0
|
||||
if link != nil {
|
||||
base := link.Attrs()
|
||||
ensureIndex(base)
|
||||
index = base.Index
|
||||
}
|
||||
|
||||
res := make([]Addr, 0)
|
||||
for _, m := range msgs {
|
||||
msg := nl.DeserializeIfAddrmsg(m)
|
||||
|
||||
if link != nil && msg.Index != uint32(index) {
|
||||
// Ignore messages from other interfaces
|
||||
continue
|
||||
}
|
||||
|
||||
attrs, err := nl.ParseRouteAttr(m[msg.Len():])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var addr Addr
|
||||
for _, attr := range attrs {
|
||||
switch attr.Attr.Type {
|
||||
case syscall.IFA_ADDRESS:
|
||||
addr.IPNet = &net.IPNet{
|
||||
IP: attr.Value,
|
||||
Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)),
|
||||
}
|
||||
case syscall.IFA_LABEL:
|
||||
addr.Label = string(attr.Value[:len(attr.Value)-1])
|
||||
}
|
||||
}
|
||||
res = append(res, addr)
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
45
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/addr_test.go
generated
vendored
Normal file
45
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/addr_test.go
generated
vendored
Normal file
|
@ -0,0 +1,45 @@
|
|||
package netlink
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAddrAddDel(t *testing.T) {
|
||||
tearDown := setUpNetlinkTest(t)
|
||||
defer tearDown()
|
||||
|
||||
link, err := LinkByName("lo")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
addr, err := ParseAddr("127.1.1.1/24 local")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err = AddrAdd(link, addr); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
addrs, err := AddrList(link, FAMILY_ALL)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(addrs) != 1 || !addr.Equal(addrs[0]) || addrs[0].Label != addr.Label {
|
||||
t.Fatal("Address not added properly")
|
||||
}
|
||||
|
||||
if err = AddrDel(link, addr); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
addrs, err = AddrList(link, FAMILY_ALL)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(addrs) != 0 {
|
||||
t.Fatal("Address not removed properly")
|
||||
}
|
||||
}
|
175
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/link.go
generated
vendored
Normal file
175
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/link.go
generated
vendored
Normal file
|
@ -0,0 +1,175 @@
|
|||
package netlink
|
||||
|
||||
import "net"
|
||||
|
||||
// Link represents a link device from netlink. Shared link attributes
|
||||
// like name may be retrieved using the Attrs() method. Unique data
|
||||
// can be retrieved by casting the object to the proper type.
|
||||
type Link interface {
|
||||
Attrs() *LinkAttrs
|
||||
Type() string
|
||||
}
|
||||
|
||||
// LinkAttrs represents data shared by most link types
|
||||
type LinkAttrs struct {
|
||||
Index int
|
||||
MTU int
|
||||
TxQLen uint32 // Transmit Queue Length
|
||||
Name string
|
||||
HardwareAddr net.HardwareAddr
|
||||
Flags net.Flags
|
||||
ParentIndex int // index of the parent link device
|
||||
MasterIndex int // must be the index of a bridge
|
||||
}
|
||||
|
||||
// Device links cannot be created via netlink. These links
|
||||
// are links created by udev like 'lo' and 'etho0'
|
||||
type Device struct {
|
||||
LinkAttrs
|
||||
}
|
||||
|
||||
func (device *Device) Attrs() *LinkAttrs {
|
||||
return &device.LinkAttrs
|
||||
}
|
||||
|
||||
func (device *Device) Type() string {
|
||||
return "device"
|
||||
}
|
||||
|
||||
// Dummy links are dummy ethernet devices
|
||||
type Dummy struct {
|
||||
LinkAttrs
|
||||
}
|
||||
|
||||
func (dummy *Dummy) Attrs() *LinkAttrs {
|
||||
return &dummy.LinkAttrs
|
||||
}
|
||||
|
||||
func (dummy *Dummy) Type() string {
|
||||
return "dummy"
|
||||
}
|
||||
|
||||
// Bridge links are simple linux bridges
|
||||
type Bridge struct {
|
||||
LinkAttrs
|
||||
}
|
||||
|
||||
func (bridge *Bridge) Attrs() *LinkAttrs {
|
||||
return &bridge.LinkAttrs
|
||||
}
|
||||
|
||||
func (bridge *Bridge) Type() string {
|
||||
return "bridge"
|
||||
}
|
||||
|
||||
// Vlan links have ParentIndex set in their Attrs()
|
||||
type Vlan struct {
|
||||
LinkAttrs
|
||||
VlanId int
|
||||
}
|
||||
|
||||
func (vlan *Vlan) Attrs() *LinkAttrs {
|
||||
return &vlan.LinkAttrs
|
||||
}
|
||||
|
||||
func (vlan *Vlan) Type() string {
|
||||
return "vlan"
|
||||
}
|
||||
|
||||
// Macvlan links have ParentIndex set in their Attrs()
|
||||
type Macvlan struct {
|
||||
LinkAttrs
|
||||
}
|
||||
|
||||
func (macvlan *Macvlan) Attrs() *LinkAttrs {
|
||||
return &macvlan.LinkAttrs
|
||||
}
|
||||
|
||||
func (macvlan *Macvlan) Type() string {
|
||||
return "macvlan"
|
||||
}
|
||||
|
||||
// Veth devices must specify PeerName on create
|
||||
type Veth struct {
|
||||
LinkAttrs
|
||||
PeerName string // veth on create only
|
||||
}
|
||||
|
||||
func (veth *Veth) Attrs() *LinkAttrs {
|
||||
return &veth.LinkAttrs
|
||||
}
|
||||
|
||||
func (veth *Veth) Type() string {
|
||||
return "veth"
|
||||
}
|
||||
|
||||
// Generic links represent types that are not currently understood
|
||||
// by this netlink library.
|
||||
type Generic struct {
|
||||
LinkAttrs
|
||||
LinkType string
|
||||
}
|
||||
|
||||
func (generic *Generic) Attrs() *LinkAttrs {
|
||||
return &generic.LinkAttrs
|
||||
}
|
||||
|
||||
func (generic *Generic) Type() string {
|
||||
return generic.LinkType
|
||||
}
|
||||
|
||||
type Vxlan struct {
|
||||
LinkAttrs
|
||||
VxlanId int
|
||||
VtepDevIndex int
|
||||
SrcAddr net.IP
|
||||
Group net.IP
|
||||
TTL int
|
||||
TOS int
|
||||
Learning bool
|
||||
Proxy bool
|
||||
RSC bool
|
||||
L2miss bool
|
||||
L3miss bool
|
||||
NoAge bool
|
||||
Age int
|
||||
Limit int
|
||||
Port int
|
||||
PortLow int
|
||||
PortHigh int
|
||||
}
|
||||
|
||||
func (vxlan *Vxlan) Attrs() *LinkAttrs {
|
||||
return &vxlan.LinkAttrs
|
||||
}
|
||||
|
||||
func (vxlan *Vxlan) Type() string {
|
||||
return "vxlan"
|
||||
}
|
||||
|
||||
type IPVlanMode uint16
|
||||
|
||||
const (
|
||||
IPVLAN_MODE_L2 IPVlanMode = iota
|
||||
IPVLAN_MODE_L3
|
||||
IPVLAN_MODE_MAX
|
||||
)
|
||||
|
||||
type IPVlan struct {
|
||||
LinkAttrs
|
||||
Mode IPVlanMode
|
||||
}
|
||||
|
||||
func (ipvlan *IPVlan) Attrs() *LinkAttrs {
|
||||
return &ipvlan.LinkAttrs
|
||||
}
|
||||
|
||||
func (ipvlan *IPVlan) Type() string {
|
||||
return "ipvlan"
|
||||
}
|
||||
|
||||
// iproute2 supported devices;
|
||||
// vlan | veth | vcan | dummy | ifb | macvlan | macvtap |
|
||||
// bridge | bond | ipoib | ip6tnl | ipip | sit | vxlan |
|
||||
// gre | gretap | ip6gre | ip6gretap | vti | nlmon |
|
||||
// bond_slave | ipvlan
|
696
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/link_linux.go
generated
vendored
Normal file
696
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/link_linux.go
generated
vendored
Normal file
|
@ -0,0 +1,696 @@
|
|||
package netlink
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"net"
|
||||
"syscall"
|
||||
|
||||
"github.com/vishvananda/netlink/nl"
|
||||
)
|
||||
|
||||
var native = nl.NativeEndian()
|
||||
var lookupByDump = false
|
||||
|
||||
func ensureIndex(link *LinkAttrs) {
|
||||
if link != nil && link.Index == 0 {
|
||||
newlink, _ := LinkByName(link.Name)
|
||||
if newlink != nil {
|
||||
link.Index = newlink.Attrs().Index
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// LinkSetUp enables the link device.
|
||||
// Equivalent to: `ip link set $link up`
|
||||
func LinkSetUp(link Link) error {
|
||||
base := link.Attrs()
|
||||
ensureIndex(base)
|
||||
req := nl.NewNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_ACK)
|
||||
|
||||
msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
|
||||
msg.Change = syscall.IFF_UP
|
||||
msg.Flags = syscall.IFF_UP
|
||||
msg.Index = int32(base.Index)
|
||||
req.AddData(msg)
|
||||
|
||||
_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
|
||||
return err
|
||||
}
|
||||
|
||||
// LinkSetUp disables link device.
|
||||
// Equivalent to: `ip link set $link down`
|
||||
func LinkSetDown(link Link) error {
|
||||
base := link.Attrs()
|
||||
ensureIndex(base)
|
||||
req := nl.NewNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_ACK)
|
||||
|
||||
msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
|
||||
msg.Change = syscall.IFF_UP
|
||||
msg.Flags = 0 & ^syscall.IFF_UP
|
||||
msg.Index = int32(base.Index)
|
||||
req.AddData(msg)
|
||||
|
||||
_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
|
||||
return err
|
||||
}
|
||||
|
||||
// LinkSetMTU sets the mtu of the link device.
|
||||
// Equivalent to: `ip link set $link mtu $mtu`
|
||||
func LinkSetMTU(link Link, mtu int) error {
|
||||
base := link.Attrs()
|
||||
ensureIndex(base)
|
||||
req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
|
||||
|
||||
msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
|
||||
msg.Type = syscall.RTM_SETLINK
|
||||
msg.Flags = syscall.NLM_F_REQUEST
|
||||
msg.Index = int32(base.Index)
|
||||
msg.Change = nl.DEFAULT_CHANGE
|
||||
req.AddData(msg)
|
||||
|
||||
b := make([]byte, 4)
|
||||
native.PutUint32(b, uint32(mtu))
|
||||
|
||||
data := nl.NewRtAttr(syscall.IFLA_MTU, b)
|
||||
req.AddData(data)
|
||||
|
||||
_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
|
||||
return err
|
||||
}
|
||||
|
||||
// LinkSetName sets the name of the link device.
|
||||
// Equivalent to: `ip link set $link name $name`
|
||||
func LinkSetName(link Link, name string) error {
|
||||
base := link.Attrs()
|
||||
ensureIndex(base)
|
||||
req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
|
||||
|
||||
msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
|
||||
msg.Type = syscall.RTM_SETLINK
|
||||
msg.Flags = syscall.NLM_F_REQUEST
|
||||
msg.Index = int32(base.Index)
|
||||
msg.Change = nl.DEFAULT_CHANGE
|
||||
req.AddData(msg)
|
||||
|
||||
data := nl.NewRtAttr(syscall.IFLA_IFNAME, []byte(name))
|
||||
req.AddData(data)
|
||||
|
||||
_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
|
||||
return err
|
||||
}
|
||||
|
||||
// LinkSetHardwareAddr sets the hardware address of the link device.
|
||||
// Equivalent to: `ip link set $link address $hwaddr`
|
||||
func LinkSetHardwareAddr(link Link, hwaddr net.HardwareAddr) error {
|
||||
base := link.Attrs()
|
||||
ensureIndex(base)
|
||||
req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
|
||||
|
||||
msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
|
||||
msg.Type = syscall.RTM_SETLINK
|
||||
msg.Flags = syscall.NLM_F_REQUEST
|
||||
msg.Index = int32(base.Index)
|
||||
msg.Change = nl.DEFAULT_CHANGE
|
||||
req.AddData(msg)
|
||||
|
||||
data := nl.NewRtAttr(syscall.IFLA_ADDRESS, []byte(hwaddr))
|
||||
req.AddData(data)
|
||||
|
||||
_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
|
||||
return err
|
||||
}
|
||||
|
||||
// LinkSetMaster sets the master of the link device.
|
||||
// Equivalent to: `ip link set $link master $master`
|
||||
func LinkSetMaster(link Link, master *Bridge) error {
|
||||
index := 0
|
||||
if master != nil {
|
||||
masterBase := master.Attrs()
|
||||
ensureIndex(masterBase)
|
||||
index = masterBase.Index
|
||||
}
|
||||
return LinkSetMasterByIndex(link, index)
|
||||
}
|
||||
|
||||
// LinkSetMasterByIndex sets the master of the link device.
|
||||
// Equivalent to: `ip link set $link master $master`
|
||||
func LinkSetMasterByIndex(link Link, masterIndex int) error {
|
||||
base := link.Attrs()
|
||||
ensureIndex(base)
|
||||
req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
|
||||
|
||||
msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
|
||||
msg.Type = syscall.RTM_SETLINK
|
||||
msg.Flags = syscall.NLM_F_REQUEST
|
||||
msg.Index = int32(base.Index)
|
||||
msg.Change = nl.DEFAULT_CHANGE
|
||||
req.AddData(msg)
|
||||
|
||||
b := make([]byte, 4)
|
||||
native.PutUint32(b, uint32(masterIndex))
|
||||
|
||||
data := nl.NewRtAttr(syscall.IFLA_MASTER, b)
|
||||
req.AddData(data)
|
||||
|
||||
_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
|
||||
return err
|
||||
}
|
||||
|
||||
// LinkSetNsPid puts the device into a new network namespace. The
|
||||
// pid must be a pid of a running process.
|
||||
// Equivalent to: `ip link set $link netns $pid`
|
||||
func LinkSetNsPid(link Link, nspid int) error {
|
||||
base := link.Attrs()
|
||||
ensureIndex(base)
|
||||
req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
|
||||
|
||||
msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
|
||||
msg.Type = syscall.RTM_SETLINK
|
||||
msg.Flags = syscall.NLM_F_REQUEST
|
||||
msg.Index = int32(base.Index)
|
||||
msg.Change = nl.DEFAULT_CHANGE
|
||||
req.AddData(msg)
|
||||
|
||||
b := make([]byte, 4)
|
||||
native.PutUint32(b, uint32(nspid))
|
||||
|
||||
data := nl.NewRtAttr(syscall.IFLA_NET_NS_PID, b)
|
||||
req.AddData(data)
|
||||
|
||||
_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
|
||||
return err
|
||||
}
|
||||
|
||||
// LinkSetNsPid puts the device into a new network namespace. The
|
||||
// fd must be an open file descriptor to a network namespace.
|
||||
// Similar to: `ip link set $link netns $ns`
|
||||
func LinkSetNsFd(link Link, fd int) error {
|
||||
base := link.Attrs()
|
||||
ensureIndex(base)
|
||||
req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
|
||||
|
||||
msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
|
||||
msg.Type = syscall.RTM_SETLINK
|
||||
msg.Flags = syscall.NLM_F_REQUEST
|
||||
msg.Index = int32(base.Index)
|
||||
msg.Change = nl.DEFAULT_CHANGE
|
||||
req.AddData(msg)
|
||||
|
||||
b := make([]byte, 4)
|
||||
native.PutUint32(b, uint32(fd))
|
||||
|
||||
data := nl.NewRtAttr(nl.IFLA_NET_NS_FD, b)
|
||||
req.AddData(data)
|
||||
|
||||
_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
|
||||
return err
|
||||
}
|
||||
|
||||
func boolAttr(val bool) []byte {
|
||||
var v uint8
|
||||
if val {
|
||||
v = 1
|
||||
}
|
||||
return nl.Uint8Attr(v)
|
||||
}
|
||||
|
||||
type vxlanPortRange struct {
|
||||
Lo, Hi uint16
|
||||
}
|
||||
|
||||
func addVxlanAttrs(vxlan *Vxlan, linkInfo *nl.RtAttr) {
|
||||
data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil)
|
||||
nl.NewRtAttrChild(data, nl.IFLA_VXLAN_ID, nl.Uint32Attr(uint32(vxlan.VxlanId)))
|
||||
if vxlan.VtepDevIndex != 0 {
|
||||
nl.NewRtAttrChild(data, nl.IFLA_VXLAN_LINK, nl.Uint32Attr(uint32(vxlan.VtepDevIndex)))
|
||||
}
|
||||
if vxlan.SrcAddr != nil {
|
||||
ip := vxlan.SrcAddr.To4()
|
||||
if ip != nil {
|
||||
nl.NewRtAttrChild(data, nl.IFLA_VXLAN_LOCAL, []byte(ip))
|
||||
} else {
|
||||
ip = vxlan.SrcAddr.To16()
|
||||
if ip != nil {
|
||||
nl.NewRtAttrChild(data, nl.IFLA_VXLAN_LOCAL6, []byte(ip))
|
||||
}
|
||||
}
|
||||
}
|
||||
if vxlan.Group != nil {
|
||||
group := vxlan.Group.To4()
|
||||
if group != nil {
|
||||
nl.NewRtAttrChild(data, nl.IFLA_VXLAN_GROUP, []byte(group))
|
||||
} else {
|
||||
group = vxlan.Group.To16()
|
||||
if group != nil {
|
||||
nl.NewRtAttrChild(data, nl.IFLA_VXLAN_GROUP6, []byte(group))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nl.NewRtAttrChild(data, nl.IFLA_VXLAN_TTL, nl.Uint8Attr(uint8(vxlan.TTL)))
|
||||
nl.NewRtAttrChild(data, nl.IFLA_VXLAN_TOS, nl.Uint8Attr(uint8(vxlan.TOS)))
|
||||
nl.NewRtAttrChild(data, nl.IFLA_VXLAN_LEARNING, boolAttr(vxlan.Learning))
|
||||
nl.NewRtAttrChild(data, nl.IFLA_VXLAN_PROXY, boolAttr(vxlan.Proxy))
|
||||
nl.NewRtAttrChild(data, nl.IFLA_VXLAN_RSC, boolAttr(vxlan.RSC))
|
||||
nl.NewRtAttrChild(data, nl.IFLA_VXLAN_L2MISS, boolAttr(vxlan.L2miss))
|
||||
nl.NewRtAttrChild(data, nl.IFLA_VXLAN_L3MISS, boolAttr(vxlan.L3miss))
|
||||
|
||||
if vxlan.NoAge {
|
||||
nl.NewRtAttrChild(data, nl.IFLA_VXLAN_AGEING, nl.Uint32Attr(0))
|
||||
} else if vxlan.Age > 0 {
|
||||
nl.NewRtAttrChild(data, nl.IFLA_VXLAN_AGEING, nl.Uint32Attr(uint32(vxlan.Age)))
|
||||
}
|
||||
if vxlan.Limit > 0 {
|
||||
nl.NewRtAttrChild(data, nl.IFLA_VXLAN_LIMIT, nl.Uint32Attr(uint32(vxlan.Limit)))
|
||||
}
|
||||
if vxlan.Port > 0 {
|
||||
nl.NewRtAttrChild(data, nl.IFLA_VXLAN_PORT, nl.Uint16Attr(uint16(vxlan.Port)))
|
||||
}
|
||||
if vxlan.PortLow > 0 || vxlan.PortHigh > 0 {
|
||||
pr := vxlanPortRange{uint16(vxlan.PortLow), uint16(vxlan.PortHigh)}
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
binary.Write(buf, binary.BigEndian, &pr)
|
||||
|
||||
nl.NewRtAttrChild(data, nl.IFLA_VXLAN_PORT_RANGE, buf.Bytes())
|
||||
}
|
||||
}
|
||||
|
||||
// LinkAdd adds a new link device. The type and features of the device
|
||||
// are taken fromt the parameters in the link object.
|
||||
// Equivalent to: `ip link add $link`
|
||||
func LinkAdd(link Link) error {
|
||||
// TODO: set mtu and hardware address
|
||||
// TODO: support extra data for macvlan
|
||||
base := link.Attrs()
|
||||
|
||||
if base.Name == "" {
|
||||
return fmt.Errorf("LinkAttrs.Name cannot be empty!")
|
||||
}
|
||||
|
||||
req := nl.NewNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
|
||||
|
||||
msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
|
||||
req.AddData(msg)
|
||||
|
||||
if base.ParentIndex != 0 {
|
||||
b := make([]byte, 4)
|
||||
native.PutUint32(b, uint32(base.ParentIndex))
|
||||
data := nl.NewRtAttr(syscall.IFLA_LINK, b)
|
||||
req.AddData(data)
|
||||
} else if link.Type() == "ipvlan" {
|
||||
return fmt.Errorf("Can't create ipvlan link without ParentIndex")
|
||||
}
|
||||
|
||||
nameData := nl.NewRtAttr(syscall.IFLA_IFNAME, nl.ZeroTerminated(base.Name))
|
||||
req.AddData(nameData)
|
||||
|
||||
if base.MTU > 0 {
|
||||
mtu := nl.NewRtAttr(syscall.IFLA_MTU, nl.Uint32Attr(uint32(base.MTU)))
|
||||
req.AddData(mtu)
|
||||
}
|
||||
|
||||
linkInfo := nl.NewRtAttr(syscall.IFLA_LINKINFO, nil)
|
||||
nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_KIND, nl.NonZeroTerminated(link.Type()))
|
||||
|
||||
nl.NewRtAttrChild(linkInfo, syscall.IFLA_TXQLEN, nl.Uint32Attr(base.TxQLen))
|
||||
|
||||
if vlan, ok := link.(*Vlan); ok {
|
||||
b := make([]byte, 2)
|
||||
native.PutUint16(b, uint16(vlan.VlanId))
|
||||
data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil)
|
||||
nl.NewRtAttrChild(data, nl.IFLA_VLAN_ID, b)
|
||||
} else if veth, ok := link.(*Veth); ok {
|
||||
data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil)
|
||||
peer := nl.NewRtAttrChild(data, nl.VETH_INFO_PEER, nil)
|
||||
nl.NewIfInfomsgChild(peer, syscall.AF_UNSPEC)
|
||||
nl.NewRtAttrChild(peer, syscall.IFLA_IFNAME, nl.ZeroTerminated(veth.PeerName))
|
||||
nl.NewRtAttrChild(peer, syscall.IFLA_TXQLEN, nl.Uint32Attr(base.TxQLen))
|
||||
if base.MTU > 0 {
|
||||
nl.NewRtAttrChild(peer, syscall.IFLA_MTU, nl.Uint32Attr(uint32(base.MTU)))
|
||||
}
|
||||
} else if vxlan, ok := link.(*Vxlan); ok {
|
||||
addVxlanAttrs(vxlan, linkInfo)
|
||||
} else if ipv, ok := link.(*IPVlan); ok {
|
||||
data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil)
|
||||
nl.NewRtAttrChild(data, nl.IFLA_IPVLAN_MODE, nl.Uint16Attr(uint16(ipv.Mode)))
|
||||
}
|
||||
|
||||
req.AddData(linkInfo)
|
||||
|
||||
_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ensureIndex(base)
|
||||
|
||||
// can't set master during create, so set it afterwards
|
||||
if base.MasterIndex != 0 {
|
||||
// TODO: verify MasterIndex is actually a bridge?
|
||||
return LinkSetMasterByIndex(link, base.MasterIndex)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// LinkDel deletes link device. Either Index or Name must be set in
|
||||
// the link object for it to be deleted. The other values are ignored.
|
||||
// Equivalent to: `ip link del $link`
|
||||
func LinkDel(link Link) error {
|
||||
base := link.Attrs()
|
||||
|
||||
ensureIndex(base)
|
||||
|
||||
req := nl.NewNetlinkRequest(syscall.RTM_DELLINK, syscall.NLM_F_ACK)
|
||||
|
||||
msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
|
||||
msg.Index = int32(base.Index)
|
||||
req.AddData(msg)
|
||||
|
||||
_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
|
||||
return err
|
||||
}
|
||||
|
||||
func linkByNameDump(name string) (Link, error) {
|
||||
links, err := LinkList()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, link := range links {
|
||||
if link.Attrs().Name == name {
|
||||
return link, nil
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("Link %s not found", name)
|
||||
}
|
||||
|
||||
// LinkByName finds a link by name and returns a pointer to the object.
|
||||
func LinkByName(name string) (Link, error) {
|
||||
if lookupByDump {
|
||||
return linkByNameDump(name)
|
||||
}
|
||||
|
||||
req := nl.NewNetlinkRequest(syscall.RTM_GETLINK, syscall.NLM_F_ACK)
|
||||
|
||||
msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
|
||||
req.AddData(msg)
|
||||
|
||||
nameData := nl.NewRtAttr(syscall.IFLA_IFNAME, nl.ZeroTerminated(name))
|
||||
req.AddData(nameData)
|
||||
|
||||
link, err := execGetLink(req)
|
||||
if err == syscall.EINVAL {
|
||||
// older kernels don't support looking up via IFLA_IFNAME
|
||||
// so fall back to dumping all links
|
||||
lookupByDump = true
|
||||
return linkByNameDump(name)
|
||||
}
|
||||
|
||||
return link, err
|
||||
}
|
||||
|
||||
// LinkByIndex finds a link by index and returns a pointer to the object.
|
||||
func LinkByIndex(index int) (Link, error) {
|
||||
req := nl.NewNetlinkRequest(syscall.RTM_GETLINK, syscall.NLM_F_ACK)
|
||||
|
||||
msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
|
||||
msg.Index = int32(index)
|
||||
req.AddData(msg)
|
||||
|
||||
return execGetLink(req)
|
||||
}
|
||||
|
||||
func execGetLink(req *nl.NetlinkRequest) (Link, error) {
|
||||
msgs, err := req.Execute(syscall.NETLINK_ROUTE, 0)
|
||||
if err != nil {
|
||||
if errno, ok := err.(syscall.Errno); ok {
|
||||
if errno == syscall.ENODEV {
|
||||
return nil, fmt.Errorf("Link not found")
|
||||
}
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch {
|
||||
case len(msgs) == 0:
|
||||
return nil, fmt.Errorf("Link not found")
|
||||
|
||||
case len(msgs) == 1:
|
||||
return linkDeserialize(msgs[0])
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("More than one link found")
|
||||
}
|
||||
}
|
||||
|
||||
// linkDeserialize deserializes a raw message received from netlink into
|
||||
// a link object.
|
||||
func linkDeserialize(m []byte) (Link, error) {
|
||||
msg := nl.DeserializeIfInfomsg(m)
|
||||
|
||||
attrs, err := nl.ParseRouteAttr(m[msg.Len():])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
base := LinkAttrs{Index: int(msg.Index), Flags: linkFlags(msg.Flags)}
|
||||
var link Link
|
||||
linkType := ""
|
||||
for _, attr := range attrs {
|
||||
switch attr.Attr.Type {
|
||||
case syscall.IFLA_LINKINFO:
|
||||
infos, err := nl.ParseRouteAttr(attr.Value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, info := range infos {
|
||||
switch info.Attr.Type {
|
||||
case nl.IFLA_INFO_KIND:
|
||||
linkType = string(info.Value[:len(info.Value)-1])
|
||||
switch linkType {
|
||||
case "dummy":
|
||||
link = &Dummy{}
|
||||
case "bridge":
|
||||
link = &Bridge{}
|
||||
case "vlan":
|
||||
link = &Vlan{}
|
||||
case "veth":
|
||||
link = &Veth{}
|
||||
case "vxlan":
|
||||
link = &Vxlan{}
|
||||
case "ipvlan":
|
||||
link = &IPVlan{}
|
||||
default:
|
||||
link = &Generic{LinkType: linkType}
|
||||
}
|
||||
case nl.IFLA_INFO_DATA:
|
||||
data, err := nl.ParseRouteAttr(info.Value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch linkType {
|
||||
case "vlan":
|
||||
parseVlanData(link, data)
|
||||
case "vxlan":
|
||||
parseVxlanData(link, data)
|
||||
case "ipvlan":
|
||||
parseIPVlanData(link, data)
|
||||
}
|
||||
}
|
||||
}
|
||||
case syscall.IFLA_ADDRESS:
|
||||
var nonzero bool
|
||||
for _, b := range attr.Value {
|
||||
if b != 0 {
|
||||
nonzero = true
|
||||
}
|
||||
}
|
||||
if nonzero {
|
||||
base.HardwareAddr = attr.Value[:]
|
||||
}
|
||||
case syscall.IFLA_IFNAME:
|
||||
base.Name = string(attr.Value[:len(attr.Value)-1])
|
||||
case syscall.IFLA_MTU:
|
||||
base.MTU = int(native.Uint32(attr.Value[0:4]))
|
||||
case syscall.IFLA_LINK:
|
||||
base.ParentIndex = int(native.Uint32(attr.Value[0:4]))
|
||||
case syscall.IFLA_MASTER:
|
||||
base.MasterIndex = int(native.Uint32(attr.Value[0:4]))
|
||||
case syscall.IFLA_TXQLEN:
|
||||
base.TxQLen = native.Uint32(attr.Value[0:4])
|
||||
}
|
||||
}
|
||||
// Links that don't have IFLA_INFO_KIND are hardware devices
|
||||
if link == nil {
|
||||
link = &Device{}
|
||||
}
|
||||
*link.Attrs() = base
|
||||
|
||||
return link, nil
|
||||
}
|
||||
|
||||
// LinkList gets a list of link devices.
|
||||
// Equivalent to: `ip link show`
|
||||
func LinkList() ([]Link, error) {
|
||||
// NOTE(vish): This duplicates functionality in net/iface_linux.go, but we need
|
||||
// to get the message ourselves to parse link type.
|
||||
req := nl.NewNetlinkRequest(syscall.RTM_GETLINK, syscall.NLM_F_DUMP)
|
||||
|
||||
msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
|
||||
req.AddData(msg)
|
||||
|
||||
msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWLINK)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res := make([]Link, 0)
|
||||
|
||||
for _, m := range msgs {
|
||||
link, err := linkDeserialize(m)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res = append(res, link)
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func LinkSetHairpin(link Link, mode bool) error {
|
||||
return setProtinfoAttr(link, mode, nl.IFLA_BRPORT_MODE)
|
||||
}
|
||||
|
||||
func LinkSetGuard(link Link, mode bool) error {
|
||||
return setProtinfoAttr(link, mode, nl.IFLA_BRPORT_GUARD)
|
||||
}
|
||||
|
||||
func LinkSetFastLeave(link Link, mode bool) error {
|
||||
return setProtinfoAttr(link, mode, nl.IFLA_BRPORT_FAST_LEAVE)
|
||||
}
|
||||
|
||||
func LinkSetLearning(link Link, mode bool) error {
|
||||
return setProtinfoAttr(link, mode, nl.IFLA_BRPORT_LEARNING)
|
||||
}
|
||||
|
||||
func LinkSetRootBlock(link Link, mode bool) error {
|
||||
return setProtinfoAttr(link, mode, nl.IFLA_BRPORT_PROTECT)
|
||||
}
|
||||
|
||||
func LinkSetFlood(link Link, mode bool) error {
|
||||
return setProtinfoAttr(link, mode, nl.IFLA_BRPORT_UNICAST_FLOOD)
|
||||
}
|
||||
|
||||
func setProtinfoAttr(link Link, mode bool, attr int) error {
|
||||
base := link.Attrs()
|
||||
ensureIndex(base)
|
||||
req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
|
||||
|
||||
msg := nl.NewIfInfomsg(syscall.AF_BRIDGE)
|
||||
msg.Type = syscall.RTM_SETLINK
|
||||
msg.Flags = syscall.NLM_F_REQUEST
|
||||
msg.Index = int32(base.Index)
|
||||
msg.Change = nl.DEFAULT_CHANGE
|
||||
req.AddData(msg)
|
||||
|
||||
br := nl.NewRtAttr(syscall.IFLA_PROTINFO|syscall.NLA_F_NESTED, nil)
|
||||
nl.NewRtAttrChild(br, attr, boolToByte(mode))
|
||||
req.AddData(br)
|
||||
_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseVlanData(link Link, data []syscall.NetlinkRouteAttr) {
|
||||
vlan := link.(*Vlan)
|
||||
for _, datum := range data {
|
||||
switch datum.Attr.Type {
|
||||
case nl.IFLA_VLAN_ID:
|
||||
vlan.VlanId = int(native.Uint16(datum.Value[0:2]))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func parseVxlanData(link Link, data []syscall.NetlinkRouteAttr) {
|
||||
vxlan := link.(*Vxlan)
|
||||
for _, datum := range data {
|
||||
switch datum.Attr.Type {
|
||||
case nl.IFLA_VXLAN_ID:
|
||||
vxlan.VxlanId = int(native.Uint32(datum.Value[0:4]))
|
||||
case nl.IFLA_VXLAN_LINK:
|
||||
vxlan.VtepDevIndex = int(native.Uint32(datum.Value[0:4]))
|
||||
case nl.IFLA_VXLAN_LOCAL:
|
||||
vxlan.SrcAddr = net.IP(datum.Value[0:4])
|
||||
case nl.IFLA_VXLAN_LOCAL6:
|
||||
vxlan.SrcAddr = net.IP(datum.Value[0:16])
|
||||
case nl.IFLA_VXLAN_GROUP:
|
||||
vxlan.Group = net.IP(datum.Value[0:4])
|
||||
case nl.IFLA_VXLAN_GROUP6:
|
||||
vxlan.Group = net.IP(datum.Value[0:16])
|
||||
case nl.IFLA_VXLAN_TTL:
|
||||
vxlan.TTL = int(datum.Value[0])
|
||||
case nl.IFLA_VXLAN_TOS:
|
||||
vxlan.TOS = int(datum.Value[0])
|
||||
case nl.IFLA_VXLAN_LEARNING:
|
||||
vxlan.Learning = int8(datum.Value[0]) != 0
|
||||
case nl.IFLA_VXLAN_PROXY:
|
||||
vxlan.Proxy = int8(datum.Value[0]) != 0
|
||||
case nl.IFLA_VXLAN_RSC:
|
||||
vxlan.RSC = int8(datum.Value[0]) != 0
|
||||
case nl.IFLA_VXLAN_L2MISS:
|
||||
vxlan.L2miss = int8(datum.Value[0]) != 0
|
||||
case nl.IFLA_VXLAN_L3MISS:
|
||||
vxlan.L3miss = int8(datum.Value[0]) != 0
|
||||
case nl.IFLA_VXLAN_AGEING:
|
||||
vxlan.Age = int(native.Uint32(datum.Value[0:4]))
|
||||
vxlan.NoAge = vxlan.Age == 0
|
||||
case nl.IFLA_VXLAN_LIMIT:
|
||||
vxlan.Limit = int(native.Uint32(datum.Value[0:4]))
|
||||
case nl.IFLA_VXLAN_PORT:
|
||||
vxlan.Port = int(native.Uint16(datum.Value[0:2]))
|
||||
case nl.IFLA_VXLAN_PORT_RANGE:
|
||||
buf := bytes.NewBuffer(datum.Value[0:4])
|
||||
var pr vxlanPortRange
|
||||
if binary.Read(buf, binary.BigEndian, &pr) != nil {
|
||||
vxlan.PortLow = int(pr.Lo)
|
||||
vxlan.PortHigh = int(pr.Hi)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func parseIPVlanData(link Link, data []syscall.NetlinkRouteAttr) {
|
||||
ipv := link.(*IPVlan)
|
||||
for _, datum := range data {
|
||||
if datum.Attr.Type == nl.IFLA_IPVLAN_MODE {
|
||||
ipv.Mode = IPVlanMode(native.Uint32(datum.Value[0:4]))
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// copied from pkg/net_linux.go
|
||||
func linkFlags(rawFlags uint32) net.Flags {
|
||||
var f net.Flags
|
||||
if rawFlags&syscall.IFF_UP != 0 {
|
||||
f |= net.FlagUp
|
||||
}
|
||||
if rawFlags&syscall.IFF_BROADCAST != 0 {
|
||||
f |= net.FlagBroadcast
|
||||
}
|
||||
if rawFlags&syscall.IFF_LOOPBACK != 0 {
|
||||
f |= net.FlagLoopback
|
||||
}
|
||||
if rawFlags&syscall.IFF_POINTOPOINT != 0 {
|
||||
f |= net.FlagPointToPoint
|
||||
}
|
||||
if rawFlags&syscall.IFF_MULTICAST != 0 {
|
||||
f |= net.FlagMulticast
|
||||
}
|
||||
return f
|
||||
}
|
531
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/link_test.go
generated
vendored
Normal file
531
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/link_test.go
generated
vendored
Normal file
|
@ -0,0 +1,531 @@
|
|||
package netlink
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/vishvananda/netns"
|
||||
)
|
||||
|
||||
const testTxQLen uint32 = 100
|
||||
|
||||
func testLinkAddDel(t *testing.T, link Link) {
|
||||
links, err := LinkList()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
num := len(links)
|
||||
|
||||
if err := LinkAdd(link); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
base := link.Attrs()
|
||||
|
||||
result, err := LinkByName(base.Name)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
rBase := result.Attrs()
|
||||
|
||||
if vlan, ok := link.(*Vlan); ok {
|
||||
other, ok := result.(*Vlan)
|
||||
if !ok {
|
||||
t.Fatal("Result of create is not a vlan")
|
||||
}
|
||||
if vlan.VlanId != other.VlanId {
|
||||
t.Fatal("Link.VlanId id doesn't match")
|
||||
}
|
||||
}
|
||||
|
||||
if rBase.ParentIndex == 0 && base.ParentIndex != 0 {
|
||||
t.Fatal("Created link doesn't have a Parent but it should")
|
||||
} else if rBase.ParentIndex != 0 && base.ParentIndex == 0 {
|
||||
t.Fatal("Created link has a Parent but it shouldn't")
|
||||
} else if rBase.ParentIndex != 0 && base.ParentIndex != 0 {
|
||||
if rBase.ParentIndex != base.ParentIndex {
|
||||
t.Fatal("Link.ParentIndex doesn't match")
|
||||
}
|
||||
}
|
||||
|
||||
if veth, ok := link.(*Veth); ok {
|
||||
if veth.TxQLen != testTxQLen {
|
||||
t.Fatalf("TxQLen is %d, should be %d", veth.TxQLen, testTxQLen)
|
||||
}
|
||||
if rBase.MTU != base.MTU {
|
||||
t.Fatalf("MTU is %d, should be %d", rBase.MTU, base.MTU)
|
||||
}
|
||||
|
||||
if veth.PeerName != "" {
|
||||
var peer *Veth
|
||||
other, err := LinkByName(veth.PeerName)
|
||||
if err != nil {
|
||||
t.Fatalf("Peer %s not created", veth.PeerName)
|
||||
}
|
||||
if peer, ok = other.(*Veth); !ok {
|
||||
t.Fatalf("Peer %s is incorrect type", veth.PeerName)
|
||||
}
|
||||
if peer.TxQLen != testTxQLen {
|
||||
t.Fatalf("TxQLen of peer is %d, should be %d", peer.TxQLen, testTxQLen)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if vxlan, ok := link.(*Vxlan); ok {
|
||||
other, ok := result.(*Vxlan)
|
||||
if !ok {
|
||||
t.Fatal("Result of create is not a vxlan")
|
||||
}
|
||||
compareVxlan(t, vxlan, other)
|
||||
}
|
||||
|
||||
if ipv, ok := link.(*IPVlan); ok {
|
||||
other, ok := result.(*IPVlan)
|
||||
if !ok {
|
||||
t.Fatal("Result of create is not a ipvlan")
|
||||
}
|
||||
if ipv.Mode != other.Mode {
|
||||
t.Fatalf("Got unexpected mode: %d, expected: %d", other.Mode, ipv.Mode)
|
||||
}
|
||||
}
|
||||
|
||||
if err = LinkDel(link); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
links, err = LinkList()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(links) != num {
|
||||
t.Fatal("Link not removed properly")
|
||||
}
|
||||
}
|
||||
|
||||
func compareVxlan(t *testing.T, expected, actual *Vxlan) {
|
||||
|
||||
if actual.VxlanId != expected.VxlanId {
|
||||
t.Fatal("Vxlan.VxlanId doesn't match")
|
||||
}
|
||||
if expected.SrcAddr != nil && !actual.SrcAddr.Equal(expected.SrcAddr) {
|
||||
t.Fatal("Vxlan.SrcAddr doesn't match")
|
||||
}
|
||||
if expected.Group != nil && !actual.Group.Equal(expected.Group) {
|
||||
t.Fatal("Vxlan.Group doesn't match")
|
||||
}
|
||||
if expected.TTL != -1 && actual.TTL != expected.TTL {
|
||||
t.Fatal("Vxlan.TTL doesn't match")
|
||||
}
|
||||
if expected.TOS != -1 && actual.TOS != expected.TOS {
|
||||
t.Fatal("Vxlan.TOS doesn't match")
|
||||
}
|
||||
if actual.Learning != expected.Learning {
|
||||
t.Fatal("Vxlan.Learning doesn't match")
|
||||
}
|
||||
if actual.Proxy != expected.Proxy {
|
||||
t.Fatal("Vxlan.Proxy doesn't match")
|
||||
}
|
||||
if actual.RSC != expected.RSC {
|
||||
t.Fatal("Vxlan.RSC doesn't match")
|
||||
}
|
||||
if actual.L2miss != expected.L2miss {
|
||||
t.Fatal("Vxlan.L2miss doesn't match")
|
||||
}
|
||||
if actual.L3miss != expected.L3miss {
|
||||
t.Fatal("Vxlan.L3miss doesn't match")
|
||||
}
|
||||
if expected.NoAge {
|
||||
if !actual.NoAge {
|
||||
t.Fatal("Vxlan.NoAge doesn't match")
|
||||
}
|
||||
} else if expected.Age > 0 && actual.Age != expected.Age {
|
||||
t.Fatal("Vxlan.Age doesn't match")
|
||||
}
|
||||
if expected.Limit > 0 && actual.Limit != expected.Limit {
|
||||
t.Fatal("Vxlan.Limit doesn't match")
|
||||
}
|
||||
if expected.Port > 0 && actual.Port != expected.Port {
|
||||
t.Fatal("Vxlan.Port doesn't match")
|
||||
}
|
||||
if expected.PortLow > 0 || expected.PortHigh > 0 {
|
||||
if actual.PortLow != expected.PortLow {
|
||||
t.Fatal("Vxlan.PortLow doesn't match")
|
||||
}
|
||||
if actual.PortHigh != expected.PortHigh {
|
||||
t.Fatal("Vxlan.PortHigh doesn't match")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLinkAddDelDummy(t *testing.T) {
|
||||
tearDown := setUpNetlinkTest(t)
|
||||
defer tearDown()
|
||||
|
||||
testLinkAddDel(t, &Dummy{LinkAttrs{Name: "foo"}})
|
||||
}
|
||||
|
||||
func TestLinkAddDelBridge(t *testing.T) {
|
||||
tearDown := setUpNetlinkTest(t)
|
||||
defer tearDown()
|
||||
|
||||
testLinkAddDel(t, &Bridge{LinkAttrs{Name: "foo", MTU: 1400}})
|
||||
}
|
||||
|
||||
func TestLinkAddDelVlan(t *testing.T) {
|
||||
tearDown := setUpNetlinkTest(t)
|
||||
defer tearDown()
|
||||
|
||||
parent := &Dummy{LinkAttrs{Name: "foo"}}
|
||||
if err := LinkAdd(parent); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
testLinkAddDel(t, &Vlan{LinkAttrs{Name: "bar", ParentIndex: parent.Attrs().Index}, 900})
|
||||
|
||||
if err := LinkDel(parent); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLinkAddDelMacvlan(t *testing.T) {
|
||||
tearDown := setUpNetlinkTest(t)
|
||||
defer tearDown()
|
||||
|
||||
parent := &Dummy{LinkAttrs{Name: "foo"}}
|
||||
if err := LinkAdd(parent); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
testLinkAddDel(t, &Macvlan{LinkAttrs{Name: "bar", ParentIndex: parent.Attrs().Index}})
|
||||
|
||||
if err := LinkDel(parent); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLinkAddDelVeth(t *testing.T) {
|
||||
tearDown := setUpNetlinkTest(t)
|
||||
defer tearDown()
|
||||
|
||||
testLinkAddDel(t, &Veth{LinkAttrs{Name: "foo", TxQLen: testTxQLen, MTU: 1400}, "bar"})
|
||||
}
|
||||
|
||||
func TestLinkAddDelBridgeMaster(t *testing.T) {
|
||||
tearDown := setUpNetlinkTest(t)
|
||||
defer tearDown()
|
||||
|
||||
master := &Bridge{LinkAttrs{Name: "foo"}}
|
||||
if err := LinkAdd(master); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
testLinkAddDel(t, &Dummy{LinkAttrs{Name: "bar", MasterIndex: master.Attrs().Index}})
|
||||
|
||||
if err := LinkDel(master); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLinkSetUnsetResetMaster(t *testing.T) {
|
||||
tearDown := setUpNetlinkTest(t)
|
||||
defer tearDown()
|
||||
|
||||
master := &Bridge{LinkAttrs{Name: "foo"}}
|
||||
if err := LinkAdd(master); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
newmaster := &Bridge{LinkAttrs{Name: "bar"}}
|
||||
if err := LinkAdd(newmaster); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
slave := &Dummy{LinkAttrs{Name: "baz"}}
|
||||
if err := LinkAdd(slave); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := LinkSetMaster(slave, master); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
link, err := LinkByName("baz")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if link.Attrs().MasterIndex != master.Attrs().Index {
|
||||
t.Fatal("Master not set properly")
|
||||
}
|
||||
|
||||
if err := LinkSetMaster(slave, newmaster); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
link, err = LinkByName("baz")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if link.Attrs().MasterIndex != newmaster.Attrs().Index {
|
||||
t.Fatal("Master not reset properly")
|
||||
}
|
||||
|
||||
if err := LinkSetMaster(slave, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
link, err = LinkByName("baz")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if link.Attrs().MasterIndex != 0 {
|
||||
t.Fatal("Master not unset properly")
|
||||
}
|
||||
if err := LinkDel(slave); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := LinkDel(newmaster); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := LinkDel(master); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLinkSetNs(t *testing.T) {
|
||||
tearDown := setUpNetlinkTest(t)
|
||||
defer tearDown()
|
||||
|
||||
basens, err := netns.Get()
|
||||
if err != nil {
|
||||
t.Fatal("Failed to get basens")
|
||||
}
|
||||
defer basens.Close()
|
||||
|
||||
newns, err := netns.New()
|
||||
if err != nil {
|
||||
t.Fatal("Failed to create newns")
|
||||
}
|
||||
defer newns.Close()
|
||||
|
||||
link := &Veth{LinkAttrs{Name: "foo"}, "bar"}
|
||||
if err := LinkAdd(link); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
peer, err := LinkByName("bar")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
LinkSetNsFd(peer, int(basens))
|
||||
if err != nil {
|
||||
t.Fatal("Failed to set newns for link")
|
||||
}
|
||||
|
||||
_, err = LinkByName("bar")
|
||||
if err == nil {
|
||||
t.Fatal("Link bar is still in newns")
|
||||
}
|
||||
|
||||
err = netns.Set(basens)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to set basens")
|
||||
}
|
||||
|
||||
peer, err = LinkByName("bar")
|
||||
if err != nil {
|
||||
t.Fatal("Link is not in basens")
|
||||
}
|
||||
|
||||
if err := LinkDel(peer); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = netns.Set(newns)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to set newns")
|
||||
}
|
||||
|
||||
_, err = LinkByName("foo")
|
||||
if err == nil {
|
||||
t.Fatal("Other half of veth pair not deleted")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestLinkAddDelVxlan(t *testing.T) {
|
||||
tearDown := setUpNetlinkTest(t)
|
||||
defer tearDown()
|
||||
|
||||
parent := &Dummy{
|
||||
LinkAttrs{Name: "foo"},
|
||||
}
|
||||
if err := LinkAdd(parent); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
vxlan := Vxlan{
|
||||
LinkAttrs: LinkAttrs{
|
||||
Name: "bar",
|
||||
},
|
||||
VxlanId: 10,
|
||||
VtepDevIndex: parent.Index,
|
||||
Learning: true,
|
||||
L2miss: true,
|
||||
L3miss: true,
|
||||
}
|
||||
|
||||
testLinkAddDel(t, &vxlan)
|
||||
if err := LinkDel(parent); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLinkAddDelIPVlanL2(t *testing.T) {
|
||||
tearDown := setUpNetlinkTest(t)
|
||||
defer tearDown()
|
||||
parent := &Dummy{LinkAttrs{Name: "foo"}}
|
||||
if err := LinkAdd(parent); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ipv := IPVlan{
|
||||
LinkAttrs: LinkAttrs{
|
||||
Name: "bar",
|
||||
ParentIndex: parent.Index,
|
||||
},
|
||||
Mode: IPVLAN_MODE_L2,
|
||||
}
|
||||
|
||||
testLinkAddDel(t, &ipv)
|
||||
}
|
||||
|
||||
func TestLinkAddDelIPVlanL3(t *testing.T) {
|
||||
tearDown := setUpNetlinkTest(t)
|
||||
defer tearDown()
|
||||
parent := &Dummy{LinkAttrs{Name: "foo"}}
|
||||
if err := LinkAdd(parent); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ipv := IPVlan{
|
||||
LinkAttrs: LinkAttrs{
|
||||
Name: "bar",
|
||||
ParentIndex: parent.Index,
|
||||
},
|
||||
Mode: IPVLAN_MODE_L3,
|
||||
}
|
||||
|
||||
testLinkAddDel(t, &ipv)
|
||||
}
|
||||
|
||||
func TestLinkAddDelIPVlanNoParent(t *testing.T) {
|
||||
tearDown := setUpNetlinkTest(t)
|
||||
defer tearDown()
|
||||
|
||||
ipv := IPVlan{
|
||||
LinkAttrs: LinkAttrs{
|
||||
Name: "bar",
|
||||
},
|
||||
Mode: IPVLAN_MODE_L3,
|
||||
}
|
||||
err := LinkAdd(&ipv)
|
||||
if err == nil {
|
||||
t.Fatal("Add should fail if ipvlan creating without ParentIndex")
|
||||
}
|
||||
if err.Error() != "Can't create ipvlan link without ParentIndex" {
|
||||
t.Fatalf("Error should be about missing ParentIndex, got %q", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLinkByIndex(t *testing.T) {
|
||||
tearDown := setUpNetlinkTest(t)
|
||||
defer tearDown()
|
||||
|
||||
dummy := &Dummy{LinkAttrs{Name: "dummy"}}
|
||||
if err := LinkAdd(dummy); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
found, err := LinkByIndex(dummy.Index)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if found.Attrs().Index != dummy.Attrs().Index {
|
||||
t.Fatalf("Indices don't match: %v != %v", found.Attrs().Index, dummy.Attrs().Index)
|
||||
}
|
||||
|
||||
LinkDel(dummy)
|
||||
|
||||
// test not found
|
||||
_, err = LinkByIndex(dummy.Attrs().Index)
|
||||
if err == nil {
|
||||
t.Fatalf("LinkByIndex(%v) found deleted link", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLinkSet(t *testing.T) {
|
||||
tearDown := setUpNetlinkTest(t)
|
||||
defer tearDown()
|
||||
|
||||
iface := &Dummy{LinkAttrs{Name: "foo"}}
|
||||
if err := LinkAdd(iface); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
link, err := LinkByName("foo")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = LinkSetName(link, "bar")
|
||||
if err != nil {
|
||||
t.Fatalf("Could not change interface name: %v", err)
|
||||
}
|
||||
|
||||
link, err = LinkByName("bar")
|
||||
if err != nil {
|
||||
t.Fatalf("Interface name not changed: %v", err)
|
||||
}
|
||||
|
||||
err = LinkSetMTU(link, 1400)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not set MTU: %v", err)
|
||||
}
|
||||
|
||||
link, err = LinkByName("bar")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if link.Attrs().MTU != 1400 {
|
||||
t.Fatal("MTU not changed!")
|
||||
}
|
||||
|
||||
addr, err := net.ParseMAC("00:12:34:56:78:AB")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = LinkSetHardwareAddr(link, addr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
link, err = LinkByName("bar")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(link.Attrs().HardwareAddr, addr) {
|
||||
t.Fatalf("hardware address not changed!")
|
||||
}
|
||||
}
|
22
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/neigh.go
generated
vendored
Normal file
22
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/neigh.go
generated
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
package netlink
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
)
|
||||
|
||||
// Neigh represents a link layer neighbor from netlink.
|
||||
type Neigh struct {
|
||||
LinkIndex int
|
||||
Family int
|
||||
State int
|
||||
Type int
|
||||
Flags int
|
||||
IP net.IP
|
||||
HardwareAddr net.HardwareAddr
|
||||
}
|
||||
|
||||
// String returns $ip/$hwaddr $label
|
||||
func (neigh *Neigh) String() string {
|
||||
return fmt.Sprintf("%s %s", neigh.IP, neigh.HardwareAddr)
|
||||
}
|
189
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/neigh_linux.go
generated
vendored
Normal file
189
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/neigh_linux.go
generated
vendored
Normal file
|
@ -0,0 +1,189 @@
|
|||
package netlink
|
||||
|
||||
import (
|
||||
"net"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"github.com/vishvananda/netlink/nl"
|
||||
)
|
||||
|
||||
const (
|
||||
NDA_UNSPEC = iota
|
||||
NDA_DST
|
||||
NDA_LLADDR
|
||||
NDA_CACHEINFO
|
||||
NDA_PROBES
|
||||
NDA_VLAN
|
||||
NDA_PORT
|
||||
NDA_VNI
|
||||
NDA_IFINDEX
|
||||
NDA_MAX = NDA_IFINDEX
|
||||
)
|
||||
|
||||
// Neighbor Cache Entry States.
|
||||
const (
|
||||
NUD_NONE = 0x00
|
||||
NUD_INCOMPLETE = 0x01
|
||||
NUD_REACHABLE = 0x02
|
||||
NUD_STALE = 0x04
|
||||
NUD_DELAY = 0x08
|
||||
NUD_PROBE = 0x10
|
||||
NUD_FAILED = 0x20
|
||||
NUD_NOARP = 0x40
|
||||
NUD_PERMANENT = 0x80
|
||||
)
|
||||
|
||||
// Neighbor Flags
|
||||
const (
|
||||
NTF_USE = 0x01
|
||||
NTF_SELF = 0x02
|
||||
NTF_MASTER = 0x04
|
||||
NTF_PROXY = 0x08
|
||||
NTF_ROUTER = 0x80
|
||||
)
|
||||
|
||||
type Ndmsg struct {
|
||||
Family uint8
|
||||
Index uint32
|
||||
State uint16
|
||||
Flags uint8
|
||||
Type uint8
|
||||
}
|
||||
|
||||
func deserializeNdmsg(b []byte) *Ndmsg {
|
||||
var dummy Ndmsg
|
||||
return (*Ndmsg)(unsafe.Pointer(&b[0:unsafe.Sizeof(dummy)][0]))
|
||||
}
|
||||
|
||||
func (msg *Ndmsg) Serialize() []byte {
|
||||
return (*(*[unsafe.Sizeof(*msg)]byte)(unsafe.Pointer(msg)))[:]
|
||||
}
|
||||
|
||||
func (msg *Ndmsg) Len() int {
|
||||
return int(unsafe.Sizeof(*msg))
|
||||
}
|
||||
|
||||
// NeighAdd will add an IP to MAC mapping to the ARP table
|
||||
// Equivalent to: `ip neigh add ....`
|
||||
func NeighAdd(neigh *Neigh) error {
|
||||
return neighAdd(neigh, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL)
|
||||
}
|
||||
|
||||
// NeighAdd will add or replace an IP to MAC mapping to the ARP table
|
||||
// Equivalent to: `ip neigh replace....`
|
||||
func NeighSet(neigh *Neigh) error {
|
||||
return neighAdd(neigh, syscall.NLM_F_CREATE)
|
||||
}
|
||||
|
||||
// NeighAppend will append an entry to FDB
|
||||
// Equivalent to: `bridge fdb append...`
|
||||
func NeighAppend(neigh *Neigh) error {
|
||||
return neighAdd(neigh, syscall.NLM_F_CREATE|syscall.NLM_F_APPEND)
|
||||
}
|
||||
|
||||
func neighAdd(neigh *Neigh, mode int) error {
|
||||
req := nl.NewNetlinkRequest(syscall.RTM_NEWNEIGH, mode|syscall.NLM_F_ACK)
|
||||
return neighHandle(neigh, req)
|
||||
}
|
||||
|
||||
// NeighDel will delete an IP address from a link device.
|
||||
// Equivalent to: `ip addr del $addr dev $link`
|
||||
func NeighDel(neigh *Neigh) error {
|
||||
req := nl.NewNetlinkRequest(syscall.RTM_DELNEIGH, syscall.NLM_F_ACK)
|
||||
return neighHandle(neigh, req)
|
||||
}
|
||||
|
||||
func neighHandle(neigh *Neigh, req *nl.NetlinkRequest) error {
|
||||
var family int
|
||||
if neigh.Family > 0 {
|
||||
family = neigh.Family
|
||||
} else {
|
||||
family = nl.GetIPFamily(neigh.IP)
|
||||
}
|
||||
|
||||
msg := Ndmsg{
|
||||
Family: uint8(family),
|
||||
Index: uint32(neigh.LinkIndex),
|
||||
State: uint16(neigh.State),
|
||||
Type: uint8(neigh.Type),
|
||||
Flags: uint8(neigh.Flags),
|
||||
}
|
||||
req.AddData(&msg)
|
||||
|
||||
ipData := neigh.IP.To4()
|
||||
if ipData == nil {
|
||||
ipData = neigh.IP.To16()
|
||||
}
|
||||
|
||||
dstData := nl.NewRtAttr(NDA_DST, ipData)
|
||||
req.AddData(dstData)
|
||||
|
||||
hwData := nl.NewRtAttr(NDA_LLADDR, []byte(neigh.HardwareAddr))
|
||||
req.AddData(hwData)
|
||||
|
||||
_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
|
||||
return err
|
||||
}
|
||||
|
||||
// NeighList gets a list of IP-MAC mappings in the system (ARP table).
|
||||
// Equivalent to: `ip neighbor show`.
|
||||
// The list can be filtered by link and ip family.
|
||||
func NeighList(linkIndex, family int) ([]Neigh, error) {
|
||||
req := nl.NewNetlinkRequest(syscall.RTM_GETNEIGH, syscall.NLM_F_DUMP)
|
||||
msg := Ndmsg{
|
||||
Family: uint8(family),
|
||||
}
|
||||
req.AddData(&msg)
|
||||
|
||||
msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWNEIGH)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res := make([]Neigh, 0)
|
||||
for _, m := range msgs {
|
||||
ndm := deserializeNdmsg(m)
|
||||
if linkIndex != 0 && int(ndm.Index) != linkIndex {
|
||||
// Ignore messages from other interfaces
|
||||
continue
|
||||
}
|
||||
|
||||
neigh, err := NeighDeserialize(m)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
res = append(res, *neigh)
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func NeighDeserialize(m []byte) (*Neigh, error) {
|
||||
msg := deserializeNdmsg(m)
|
||||
|
||||
neigh := Neigh{
|
||||
LinkIndex: int(msg.Index),
|
||||
Family: int(msg.Family),
|
||||
State: int(msg.State),
|
||||
Type: int(msg.Type),
|
||||
Flags: int(msg.Flags),
|
||||
}
|
||||
|
||||
attrs, err := nl.ParseRouteAttr(m[msg.Len():])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, attr := range attrs {
|
||||
switch attr.Attr.Type {
|
||||
case NDA_DST:
|
||||
neigh.IP = net.IP(attr.Value)
|
||||
case NDA_LLADDR:
|
||||
neigh.HardwareAddr = net.HardwareAddr(attr.Value)
|
||||
}
|
||||
}
|
||||
|
||||
return &neigh, nil
|
||||
}
|
104
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/neigh_test.go
generated
vendored
Normal file
104
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/neigh_test.go
generated
vendored
Normal file
|
@ -0,0 +1,104 @@
|
|||
package netlink
|
||||
|
||||
import (
|
||||
"net"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type arpEntry struct {
|
||||
ip net.IP
|
||||
mac net.HardwareAddr
|
||||
}
|
||||
|
||||
func parseMAC(s string) net.HardwareAddr {
|
||||
m, err := net.ParseMAC(s)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func dumpContains(dump []Neigh, e arpEntry) bool {
|
||||
for _, n := range dump {
|
||||
if n.IP.Equal(e.ip) && (n.State&NUD_INCOMPLETE) == 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func TestNeighAddDel(t *testing.T) {
|
||||
tearDown := setUpNetlinkTest(t)
|
||||
defer tearDown()
|
||||
|
||||
dummy := Dummy{LinkAttrs{Name: "neigh0"}}
|
||||
if err := LinkAdd(&dummy); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ensureIndex(dummy.Attrs())
|
||||
|
||||
arpTable := []arpEntry{
|
||||
{net.ParseIP("10.99.0.1"), parseMAC("aa:bb:cc:dd:00:01")},
|
||||
{net.ParseIP("10.99.0.2"), parseMAC("aa:bb:cc:dd:00:02")},
|
||||
{net.ParseIP("10.99.0.3"), parseMAC("aa:bb:cc:dd:00:03")},
|
||||
{net.ParseIP("10.99.0.4"), parseMAC("aa:bb:cc:dd:00:04")},
|
||||
{net.ParseIP("10.99.0.5"), parseMAC("aa:bb:cc:dd:00:05")},
|
||||
}
|
||||
|
||||
// Add the arpTable
|
||||
for _, entry := range arpTable {
|
||||
err := NeighAdd(&Neigh{
|
||||
LinkIndex: dummy.Index,
|
||||
State: NUD_REACHABLE,
|
||||
IP: entry.ip,
|
||||
HardwareAddr: entry.mac,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("Failed to NeighAdd: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Dump and see that all added entries are there
|
||||
dump, err := NeighList(dummy.Index, 0)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to NeighList: %v", err)
|
||||
}
|
||||
|
||||
for _, entry := range arpTable {
|
||||
if !dumpContains(dump, entry) {
|
||||
t.Errorf("Dump does not contain: %v", entry)
|
||||
}
|
||||
}
|
||||
|
||||
// Delete the arpTable
|
||||
for _, entry := range arpTable {
|
||||
err := NeighDel(&Neigh{
|
||||
LinkIndex: dummy.Index,
|
||||
IP: entry.ip,
|
||||
HardwareAddr: entry.mac,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("Failed to NeighDel: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: seems not working because of cache
|
||||
//// Dump and see that none of deleted entries are there
|
||||
//dump, err = NeighList(dummy.Index, 0)
|
||||
//if err != nil {
|
||||
//t.Errorf("Failed to NeighList: %v", err)
|
||||
//}
|
||||
|
||||
//for _, entry := range arpTable {
|
||||
//if dumpContains(dump, entry) {
|
||||
//t.Errorf("Dump contains: %v", entry)
|
||||
//}
|
||||
//}
|
||||
|
||||
if err := LinkDel(&dummy); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
39
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/netlink.go
generated
vendored
Normal file
39
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/netlink.go
generated
vendored
Normal file
|
@ -0,0 +1,39 @@
|
|||
// Package netlink provides a simple library for netlink. Netlink is
|
||||
// the interface a user-space program in linux uses to communicate with
|
||||
// the kernel. It can be used to add and remove interfaces, set up ip
|
||||
// addresses and routes, and confiugre ipsec. Netlink communication
|
||||
// requires elevated privileges, so in most cases this code needs to
|
||||
// be run as root. The low level primitives for netlink are contained
|
||||
// in the nl subpackage. This package attempts to provide a high-level
|
||||
// interface that is loosly modeled on the iproute2 cli.
|
||||
package netlink
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/vishvananda/netlink/nl"
|
||||
)
|
||||
|
||||
const (
|
||||
// Family type definitions
|
||||
FAMILY_ALL = nl.FAMILY_ALL
|
||||
FAMILY_V4 = nl.FAMILY_V4
|
||||
FAMILY_V6 = nl.FAMILY_V6
|
||||
)
|
||||
|
||||
// ParseIPNet parses a string in ip/net format and returns a net.IPNet.
|
||||
// This is valuable because addresses in netlink are often IPNets and
|
||||
// ParseCIDR returns an IPNet with the IP part set to the base IP of the
|
||||
// range.
|
||||
func ParseIPNet(s string) (*net.IPNet, error) {
|
||||
ip, ipNet, err := net.ParseCIDR(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &net.IPNet{IP: ip, Mask: ipNet.Mask}, nil
|
||||
}
|
||||
|
||||
// NewIPNet generates an IPNet from an ip address using a netmask of 32.
|
||||
func NewIPNet(ip net.IP) *net.IPNet {
|
||||
return &net.IPNet{IP: ip, Mask: net.CIDRMask(32, 32)}
|
||||
}
|
34
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/netlink_test.go
generated
vendored
Normal file
34
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/netlink_test.go
generated
vendored
Normal file
|
@ -0,0 +1,34 @@
|
|||
package netlink
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/vishvananda/netns"
|
||||
)
|
||||
|
||||
type tearDownNetlinkTest func()
|
||||
|
||||
func setUpNetlinkTest(t *testing.T) tearDownNetlinkTest {
|
||||
if os.Getuid() != 0 {
|
||||
msg := "Skipped test because it requires root privileges."
|
||||
log.Printf(msg)
|
||||
t.Skip(msg)
|
||||
}
|
||||
|
||||
// new temporary namespace so we don't pollute the host
|
||||
// lock thread since the namespace is thread local
|
||||
runtime.LockOSThread()
|
||||
var err error
|
||||
ns, err := netns.New()
|
||||
if err != nil {
|
||||
t.Fatal("Failed to create newns", ns)
|
||||
}
|
||||
|
||||
return func() {
|
||||
ns.Close()
|
||||
runtime.UnlockOSThread()
|
||||
}
|
||||
}
|
143
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/netlink_unspecified.go
generated
vendored
Normal file
143
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/netlink_unspecified.go
generated
vendored
Normal file
|
@ -0,0 +1,143 @@
|
|||
// +build !linux
|
||||
|
||||
package netlink
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrNotImplemented = errors.New("not implemented")
|
||||
)
|
||||
|
||||
func LinkSetUp(link *Link) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func LinkSetDown(link *Link) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func LinkSetMTU(link *Link, mtu int) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func LinkSetMaster(link *Link, master *Link) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func LinkSetNsPid(link *Link, nspid int) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func LinkSetNsFd(link *Link, fd int) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func LinkAdd(link *Link) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func LinkDel(link *Link) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func SetHairpin(link Link, mode bool) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func SetGuard(link Link, mode bool) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func SetFastLeave(link Link, mode bool) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func SetLearning(link Link, mode bool) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func SetRootBlock(link Link, mode bool) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func SetFlood(link Link, mode bool) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func LinkList() ([]Link, error) {
|
||||
return nil, ErrNotImplemented
|
||||
}
|
||||
|
||||
func AddrAdd(link *Link, addr *Addr) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func AddrDel(link *Link, addr *Addr) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func AddrList(link *Link, family int) ([]Addr, error) {
|
||||
return nil, ErrNotImplemented
|
||||
}
|
||||
|
||||
func RouteAdd(route *Route) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func RouteDel(route *Route) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func RouteList(link *Link, family int) ([]Route, error) {
|
||||
return nil, ErrNotImplemented
|
||||
}
|
||||
|
||||
func XfrmPolicyAdd(policy *XfrmPolicy) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func XfrmPolicyDel(policy *XfrmPolicy) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func XfrmPolicyList(family int) ([]XfrmPolicy, error) {
|
||||
return nil, ErrNotImplemented
|
||||
}
|
||||
|
||||
func XfrmStateAdd(policy *XfrmState) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func XfrmStateDel(policy *XfrmState) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func XfrmStateList(family int) ([]XfrmState, error) {
|
||||
return nil, ErrNotImplemented
|
||||
}
|
||||
|
||||
func NeighAdd(neigh *Neigh) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func NeighSet(neigh *Neigh) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func NeighAppend(neigh *Neigh) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func NeighDel(neigh *Neigh) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func NeighList(linkIndex, family int) ([]Neigh, error) {
|
||||
return nil, ErrNotImplemented
|
||||
}
|
||||
|
||||
func NeighDeserialize(m []byte) (*Ndmsg, *Neigh, error) {
|
||||
return nil, nil, ErrNotImplemented
|
||||
}
|
47
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/addr_linux.go
generated
vendored
Normal file
47
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/addr_linux.go
generated
vendored
Normal file
|
@ -0,0 +1,47 @@
|
|||
package nl
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type IfAddrmsg struct {
|
||||
syscall.IfAddrmsg
|
||||
}
|
||||
|
||||
func NewIfAddrmsg(family int) *IfAddrmsg {
|
||||
return &IfAddrmsg{
|
||||
IfAddrmsg: syscall.IfAddrmsg{
|
||||
Family: uint8(family),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// struct ifaddrmsg {
|
||||
// __u8 ifa_family;
|
||||
// __u8 ifa_prefixlen; /* The prefix length */
|
||||
// __u8 ifa_flags; /* Flags */
|
||||
// __u8 ifa_scope; /* Address scope */
|
||||
// __u32 ifa_index; /* Link index */
|
||||
// };
|
||||
|
||||
// type IfAddrmsg struct {
|
||||
// Family uint8
|
||||
// Prefixlen uint8
|
||||
// Flags uint8
|
||||
// Scope uint8
|
||||
// Index uint32
|
||||
// }
|
||||
// SizeofIfAddrmsg = 0x8
|
||||
|
||||
func DeserializeIfAddrmsg(b []byte) *IfAddrmsg {
|
||||
return (*IfAddrmsg)(unsafe.Pointer(&b[0:syscall.SizeofIfAddrmsg][0]))
|
||||
}
|
||||
|
||||
func (msg *IfAddrmsg) Serialize() []byte {
|
||||
return (*(*[syscall.SizeofIfAddrmsg]byte)(unsafe.Pointer(msg)))[:]
|
||||
}
|
||||
|
||||
func (msg *IfAddrmsg) Len() int {
|
||||
return syscall.SizeofIfAddrmsg
|
||||
}
|
39
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/addr_linux_test.go
generated
vendored
Normal file
39
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/addr_linux_test.go
generated
vendored
Normal file
|
@ -0,0 +1,39 @@
|
|||
package nl
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"syscall"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func (msg *IfAddrmsg) write(b []byte) {
|
||||
native := NativeEndian()
|
||||
b[0] = msg.Family
|
||||
b[1] = msg.Prefixlen
|
||||
b[2] = msg.Flags
|
||||
b[3] = msg.Scope
|
||||
native.PutUint32(b[4:8], msg.Index)
|
||||
}
|
||||
|
||||
func (msg *IfAddrmsg) serializeSafe() []byte {
|
||||
len := syscall.SizeofIfAddrmsg
|
||||
b := make([]byte, len)
|
||||
msg.write(b)
|
||||
return b
|
||||
}
|
||||
|
||||
func deserializeIfAddrmsgSafe(b []byte) *IfAddrmsg {
|
||||
var msg = IfAddrmsg{}
|
||||
binary.Read(bytes.NewReader(b[0:syscall.SizeofIfAddrmsg]), NativeEndian(), &msg)
|
||||
return &msg
|
||||
}
|
||||
|
||||
func TestIfAddrmsgDeserializeSerialize(t *testing.T) {
|
||||
var orig = make([]byte, syscall.SizeofIfAddrmsg)
|
||||
rand.Read(orig)
|
||||
safemsg := deserializeIfAddrmsgSafe(orig)
|
||||
msg := DeserializeIfAddrmsg(orig)
|
||||
testDeserializeSerialize(t, orig, safemsg, msg)
|
||||
}
|
81
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/link_linux.go
generated
vendored
Normal file
81
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/link_linux.go
generated
vendored
Normal file
|
@ -0,0 +1,81 @@
|
|||
package nl
|
||||
|
||||
const (
|
||||
DEFAULT_CHANGE = 0xFFFFFFFF
|
||||
)
|
||||
|
||||
const (
|
||||
IFLA_INFO_UNSPEC = iota
|
||||
IFLA_INFO_KIND
|
||||
IFLA_INFO_DATA
|
||||
IFLA_INFO_XSTATS
|
||||
IFLA_INFO_MAX = IFLA_INFO_XSTATS
|
||||
)
|
||||
|
||||
const (
|
||||
IFLA_VLAN_UNSPEC = iota
|
||||
IFLA_VLAN_ID
|
||||
IFLA_VLAN_FLAGS
|
||||
IFLA_VLAN_EGRESS_QOS
|
||||
IFLA_VLAN_INGRESS_QOS
|
||||
IFLA_VLAN_PROTOCOL
|
||||
IFLA_VLAN_MAX = IFLA_VLAN_PROTOCOL
|
||||
)
|
||||
|
||||
const (
|
||||
VETH_INFO_UNSPEC = iota
|
||||
VETH_INFO_PEER
|
||||
VETH_INFO_MAX = VETH_INFO_PEER
|
||||
)
|
||||
|
||||
const (
|
||||
IFLA_VXLAN_UNSPEC = iota
|
||||
IFLA_VXLAN_ID
|
||||
IFLA_VXLAN_GROUP
|
||||
IFLA_VXLAN_LINK
|
||||
IFLA_VXLAN_LOCAL
|
||||
IFLA_VXLAN_TTL
|
||||
IFLA_VXLAN_TOS
|
||||
IFLA_VXLAN_LEARNING
|
||||
IFLA_VXLAN_AGEING
|
||||
IFLA_VXLAN_LIMIT
|
||||
IFLA_VXLAN_PORT_RANGE
|
||||
IFLA_VXLAN_PROXY
|
||||
IFLA_VXLAN_RSC
|
||||
IFLA_VXLAN_L2MISS
|
||||
IFLA_VXLAN_L3MISS
|
||||
IFLA_VXLAN_PORT
|
||||
IFLA_VXLAN_GROUP6
|
||||
IFLA_VXLAN_LOCAL6
|
||||
IFLA_VXLAN_MAX = IFLA_VXLAN_LOCAL6
|
||||
)
|
||||
|
||||
const (
|
||||
BRIDGE_MODE_UNSPEC = iota
|
||||
BRIDGE_MODE_HAIRPIN
|
||||
)
|
||||
|
||||
const (
|
||||
IFLA_BRPORT_UNSPEC = iota
|
||||
IFLA_BRPORT_STATE
|
||||
IFLA_BRPORT_PRIORITY
|
||||
IFLA_BRPORT_COST
|
||||
IFLA_BRPORT_MODE
|
||||
IFLA_BRPORT_GUARD
|
||||
IFLA_BRPORT_PROTECT
|
||||
IFLA_BRPORT_FAST_LEAVE
|
||||
IFLA_BRPORT_LEARNING
|
||||
IFLA_BRPORT_UNICAST_FLOOD
|
||||
IFLA_BRPORT_MAX = IFLA_BRPORT_UNICAST_FLOOD
|
||||
)
|
||||
|
||||
const (
|
||||
IFLA_IPVLAN_UNSPEC = iota
|
||||
IFLA_IPVLAN_MODE
|
||||
IFLA_IPVLAN_MAX = IFLA_IPVLAN_MODE
|
||||
)
|
||||
|
||||
const (
|
||||
// not defined in syscall
|
||||
IFLA_NET_NS_FD = 28
|
||||
)
|
417
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/nl_linux.go
generated
vendored
Normal file
417
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/nl_linux.go
generated
vendored
Normal file
|
@ -0,0 +1,417 @@
|
|||
// Package nl has low level primitives for making Netlink calls.
|
||||
package nl
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"net"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
// Family type definitions
|
||||
FAMILY_ALL = syscall.AF_UNSPEC
|
||||
FAMILY_V4 = syscall.AF_INET
|
||||
FAMILY_V6 = syscall.AF_INET6
|
||||
)
|
||||
|
||||
var nextSeqNr uint32
|
||||
|
||||
// GetIPFamily returns the family type of a net.IP.
|
||||
func GetIPFamily(ip net.IP) int {
|
||||
if len(ip) <= net.IPv4len {
|
||||
return FAMILY_V4
|
||||
}
|
||||
if ip.To4() != nil {
|
||||
return FAMILY_V4
|
||||
}
|
||||
return FAMILY_V6
|
||||
}
|
||||
|
||||
var nativeEndian binary.ByteOrder
|
||||
|
||||
// Get native endianness for the system
|
||||
func NativeEndian() binary.ByteOrder {
|
||||
if nativeEndian == nil {
|
||||
var x uint32 = 0x01020304
|
||||
if *(*byte)(unsafe.Pointer(&x)) == 0x01 {
|
||||
nativeEndian = binary.BigEndian
|
||||
}
|
||||
nativeEndian = binary.LittleEndian
|
||||
}
|
||||
return nativeEndian
|
||||
}
|
||||
|
||||
// Byte swap a 16 bit value if we aren't big endian
|
||||
func Swap16(i uint16) uint16 {
|
||||
if NativeEndian() == binary.BigEndian {
|
||||
return i
|
||||
}
|
||||
return (i&0xff00)>>8 | (i&0xff)<<8
|
||||
}
|
||||
|
||||
// Byte swap a 32 bit value if aren't big endian
|
||||
func Swap32(i uint32) uint32 {
|
||||
if NativeEndian() == binary.BigEndian {
|
||||
return i
|
||||
}
|
||||
return (i&0xff000000)>>24 | (i&0xff0000)>>8 | (i&0xff00)<<8 | (i&0xff)<<24
|
||||
}
|
||||
|
||||
type NetlinkRequestData interface {
|
||||
Len() int
|
||||
Serialize() []byte
|
||||
}
|
||||
|
||||
// IfInfomsg is related to links, but it is used for list requests as well
|
||||
type IfInfomsg struct {
|
||||
syscall.IfInfomsg
|
||||
}
|
||||
|
||||
// Create an IfInfomsg with family specified
|
||||
func NewIfInfomsg(family int) *IfInfomsg {
|
||||
return &IfInfomsg{
|
||||
IfInfomsg: syscall.IfInfomsg{
|
||||
Family: uint8(family),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func DeserializeIfInfomsg(b []byte) *IfInfomsg {
|
||||
return (*IfInfomsg)(unsafe.Pointer(&b[0:syscall.SizeofIfInfomsg][0]))
|
||||
}
|
||||
|
||||
func (msg *IfInfomsg) Serialize() []byte {
|
||||
return (*(*[syscall.SizeofIfInfomsg]byte)(unsafe.Pointer(msg)))[:]
|
||||
}
|
||||
|
||||
func (msg *IfInfomsg) Len() int {
|
||||
return syscall.SizeofIfInfomsg
|
||||
}
|
||||
|
||||
func rtaAlignOf(attrlen int) int {
|
||||
return (attrlen + syscall.RTA_ALIGNTO - 1) & ^(syscall.RTA_ALIGNTO - 1)
|
||||
}
|
||||
|
||||
func NewIfInfomsgChild(parent *RtAttr, family int) *IfInfomsg {
|
||||
msg := NewIfInfomsg(family)
|
||||
parent.children = append(parent.children, msg)
|
||||
return msg
|
||||
}
|
||||
|
||||
// Extend RtAttr to handle data and children
|
||||
type RtAttr struct {
|
||||
syscall.RtAttr
|
||||
Data []byte
|
||||
children []NetlinkRequestData
|
||||
}
|
||||
|
||||
// Create a new Extended RtAttr object
|
||||
func NewRtAttr(attrType int, data []byte) *RtAttr {
|
||||
return &RtAttr{
|
||||
RtAttr: syscall.RtAttr{
|
||||
Type: uint16(attrType),
|
||||
},
|
||||
children: []NetlinkRequestData{},
|
||||
Data: data,
|
||||
}
|
||||
}
|
||||
|
||||
// Create a new RtAttr obj anc add it as a child of an existing object
|
||||
func NewRtAttrChild(parent *RtAttr, attrType int, data []byte) *RtAttr {
|
||||
attr := NewRtAttr(attrType, data)
|
||||
parent.children = append(parent.children, attr)
|
||||
return attr
|
||||
}
|
||||
|
||||
func (a *RtAttr) Len() int {
|
||||
if len(a.children) == 0 {
|
||||
return (syscall.SizeofRtAttr + len(a.Data))
|
||||
}
|
||||
|
||||
l := 0
|
||||
for _, child := range a.children {
|
||||
l += rtaAlignOf(child.Len())
|
||||
}
|
||||
l += syscall.SizeofRtAttr
|
||||
return rtaAlignOf(l + len(a.Data))
|
||||
}
|
||||
|
||||
// Serialize the RtAttr into a byte array
|
||||
// This can't ust unsafe.cast because it must iterate through children.
|
||||
func (a *RtAttr) Serialize() []byte {
|
||||
native := NativeEndian()
|
||||
|
||||
length := a.Len()
|
||||
buf := make([]byte, rtaAlignOf(length))
|
||||
|
||||
if a.Data != nil {
|
||||
copy(buf[4:], a.Data)
|
||||
} else {
|
||||
next := 4
|
||||
for _, child := range a.children {
|
||||
childBuf := child.Serialize()
|
||||
copy(buf[next:], childBuf)
|
||||
next += rtaAlignOf(len(childBuf))
|
||||
}
|
||||
}
|
||||
|
||||
if l := uint16(length); l != 0 {
|
||||
native.PutUint16(buf[0:2], l)
|
||||
}
|
||||
native.PutUint16(buf[2:4], a.Type)
|
||||
return buf
|
||||
}
|
||||
|
||||
type NetlinkRequest struct {
|
||||
syscall.NlMsghdr
|
||||
Data []NetlinkRequestData
|
||||
}
|
||||
|
||||
// Serialize the Netlink Request into a byte array
|
||||
func (msg *NetlinkRequest) Serialize() []byte {
|
||||
length := syscall.SizeofNlMsghdr
|
||||
dataBytes := make([][]byte, len(msg.Data))
|
||||
for i, data := range msg.Data {
|
||||
dataBytes[i] = data.Serialize()
|
||||
length = length + len(dataBytes[i])
|
||||
}
|
||||
msg.Len = uint32(length)
|
||||
b := make([]byte, length)
|
||||
hdr := (*(*[syscall.SizeofNlMsghdr]byte)(unsafe.Pointer(msg)))[:]
|
||||
next := syscall.SizeofNlMsghdr
|
||||
copy(b[0:next], hdr)
|
||||
for _, data := range dataBytes {
|
||||
for _, dataByte := range data {
|
||||
b[next] = dataByte
|
||||
next = next + 1
|
||||
}
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func (msg *NetlinkRequest) AddData(data NetlinkRequestData) {
|
||||
if data != nil {
|
||||
msg.Data = append(msg.Data, data)
|
||||
}
|
||||
}
|
||||
|
||||
// Execute the request against a the given sockType.
|
||||
// Returns a list of netlink messages in seriaized format, optionally filtered
|
||||
// by resType.
|
||||
func (req *NetlinkRequest) Execute(sockType int, resType uint16) ([][]byte, error) {
|
||||
s, err := getNetlinkSocket(sockType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer s.Close()
|
||||
|
||||
if err := s.Send(req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pid, err := s.GetPid()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res := make([][]byte, 0)
|
||||
|
||||
done:
|
||||
for {
|
||||
msgs, err := s.Recieve()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, m := range msgs {
|
||||
if m.Header.Seq != req.Seq {
|
||||
return nil, fmt.Errorf("Wrong Seq nr %d, expected 1", m.Header.Seq)
|
||||
}
|
||||
if m.Header.Pid != pid {
|
||||
return nil, fmt.Errorf("Wrong pid %d, expected %d", m.Header.Pid, pid)
|
||||
}
|
||||
if m.Header.Type == syscall.NLMSG_DONE {
|
||||
break done
|
||||
}
|
||||
if m.Header.Type == syscall.NLMSG_ERROR {
|
||||
native := NativeEndian()
|
||||
error := int32(native.Uint32(m.Data[0:4]))
|
||||
if error == 0 {
|
||||
break done
|
||||
}
|
||||
return nil, syscall.Errno(-error)
|
||||
}
|
||||
if resType != 0 && m.Header.Type != resType {
|
||||
continue
|
||||
}
|
||||
res = append(res, m.Data)
|
||||
if m.Header.Flags&syscall.NLM_F_MULTI == 0 {
|
||||
break done
|
||||
}
|
||||
}
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// Create a new netlink request from proto and flags
|
||||
// Note the Len value will be inaccurate once data is added until
|
||||
// the message is serialized
|
||||
func NewNetlinkRequest(proto, flags int) *NetlinkRequest {
|
||||
return &NetlinkRequest{
|
||||
NlMsghdr: syscall.NlMsghdr{
|
||||
Len: uint32(syscall.SizeofNlMsghdr),
|
||||
Type: uint16(proto),
|
||||
Flags: syscall.NLM_F_REQUEST | uint16(flags),
|
||||
Seq: atomic.AddUint32(&nextSeqNr, 1),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type NetlinkSocket struct {
|
||||
fd int
|
||||
lsa syscall.SockaddrNetlink
|
||||
}
|
||||
|
||||
func getNetlinkSocket(protocol int) (*NetlinkSocket, error) {
|
||||
fd, err := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_RAW, protocol)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s := &NetlinkSocket{
|
||||
fd: fd,
|
||||
}
|
||||
s.lsa.Family = syscall.AF_NETLINK
|
||||
if err := syscall.Bind(fd, &s.lsa); err != nil {
|
||||
syscall.Close(fd)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// Create a netlink socket with a given protocol (e.g. NETLINK_ROUTE)
|
||||
// and subscribe it to multicast groups passed in variable argument list.
|
||||
// Returns the netlink socket on whic hReceive() method can be called
|
||||
// to retrieve the messages from the kernel.
|
||||
func Subscribe(protocol int, groups ...uint) (*NetlinkSocket, error) {
|
||||
fd, err := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_RAW, protocol)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s := &NetlinkSocket{
|
||||
fd: fd,
|
||||
}
|
||||
s.lsa.Family = syscall.AF_NETLINK
|
||||
|
||||
for _, g := range groups {
|
||||
s.lsa.Groups |= (1 << (g - 1))
|
||||
}
|
||||
|
||||
if err := syscall.Bind(fd, &s.lsa); err != nil {
|
||||
syscall.Close(fd)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (s *NetlinkSocket) Close() {
|
||||
syscall.Close(s.fd)
|
||||
}
|
||||
|
||||
func (s *NetlinkSocket) Send(request *NetlinkRequest) error {
|
||||
if err := syscall.Sendto(s.fd, request.Serialize(), 0, &s.lsa); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *NetlinkSocket) Recieve() ([]syscall.NetlinkMessage, error) {
|
||||
rb := make([]byte, syscall.Getpagesize())
|
||||
nr, _, err := syscall.Recvfrom(s.fd, rb, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if nr < syscall.NLMSG_HDRLEN {
|
||||
return nil, fmt.Errorf("Got short response from netlink")
|
||||
}
|
||||
rb = rb[:nr]
|
||||
return syscall.ParseNetlinkMessage(rb)
|
||||
}
|
||||
|
||||
func (s *NetlinkSocket) GetPid() (uint32, error) {
|
||||
lsa, err := syscall.Getsockname(s.fd)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
switch v := lsa.(type) {
|
||||
case *syscall.SockaddrNetlink:
|
||||
return v.Pid, nil
|
||||
}
|
||||
return 0, fmt.Errorf("Wrong socket type")
|
||||
}
|
||||
|
||||
func ZeroTerminated(s string) []byte {
|
||||
bytes := make([]byte, len(s)+1)
|
||||
for i := 0; i < len(s); i++ {
|
||||
bytes[i] = s[i]
|
||||
}
|
||||
bytes[len(s)] = 0
|
||||
return bytes
|
||||
}
|
||||
|
||||
func NonZeroTerminated(s string) []byte {
|
||||
bytes := make([]byte, len(s))
|
||||
for i := 0; i < len(s); i++ {
|
||||
bytes[i] = s[i]
|
||||
}
|
||||
return bytes
|
||||
}
|
||||
|
||||
func BytesToString(b []byte) string {
|
||||
n := bytes.Index(b, []byte{0})
|
||||
return string(b[:n])
|
||||
}
|
||||
|
||||
func Uint8Attr(v uint8) []byte {
|
||||
return []byte{byte(v)}
|
||||
}
|
||||
|
||||
func Uint16Attr(v uint16) []byte {
|
||||
native := NativeEndian()
|
||||
bytes := make([]byte, 2)
|
||||
native.PutUint16(bytes, v)
|
||||
return bytes
|
||||
}
|
||||
|
||||
func Uint32Attr(v uint32) []byte {
|
||||
native := NativeEndian()
|
||||
bytes := make([]byte, 4)
|
||||
native.PutUint32(bytes, v)
|
||||
return bytes
|
||||
}
|
||||
|
||||
func ParseRouteAttr(b []byte) ([]syscall.NetlinkRouteAttr, error) {
|
||||
var attrs []syscall.NetlinkRouteAttr
|
||||
for len(b) >= syscall.SizeofRtAttr {
|
||||
a, vbuf, alen, err := netlinkRouteAttrAndValue(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ra := syscall.NetlinkRouteAttr{Attr: *a, Value: vbuf[:int(a.Len)-syscall.SizeofRtAttr]}
|
||||
attrs = append(attrs, ra)
|
||||
b = b[alen:]
|
||||
}
|
||||
return attrs, nil
|
||||
}
|
||||
|
||||
func netlinkRouteAttrAndValue(b []byte) (*syscall.RtAttr, []byte, int, error) {
|
||||
a := (*syscall.RtAttr)(unsafe.Pointer(&b[0]))
|
||||
if int(a.Len) < syscall.SizeofRtAttr || int(a.Len) > len(b) {
|
||||
return nil, nil, 0, syscall.EINVAL
|
||||
}
|
||||
return a, b[syscall.SizeofRtAttr:], rtaAlignOf(int(a.Len)), nil
|
||||
}
|
60
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/nl_linux_test.go
generated
vendored
Normal file
60
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/nl_linux_test.go
generated
vendored
Normal file
|
@ -0,0 +1,60 @@
|
|||
package nl
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"reflect"
|
||||
"syscall"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type testSerializer interface {
|
||||
serializeSafe() []byte
|
||||
Serialize() []byte
|
||||
}
|
||||
|
||||
func testDeserializeSerialize(t *testing.T, orig []byte, safemsg testSerializer, msg testSerializer) {
|
||||
if !reflect.DeepEqual(safemsg, msg) {
|
||||
t.Fatal("Deserialization failed.\n", safemsg, "\n", msg)
|
||||
}
|
||||
safe := msg.serializeSafe()
|
||||
if !bytes.Equal(safe, orig) {
|
||||
t.Fatal("Safe serialization failed.\n", safe, "\n", orig)
|
||||
}
|
||||
b := msg.Serialize()
|
||||
if !bytes.Equal(b, safe) {
|
||||
t.Fatal("Serialization failed.\n", b, "\n", safe)
|
||||
}
|
||||
}
|
||||
|
||||
func (msg *IfInfomsg) write(b []byte) {
|
||||
native := NativeEndian()
|
||||
b[0] = msg.Family
|
||||
b[1] = msg.X__ifi_pad
|
||||
native.PutUint16(b[2:4], msg.Type)
|
||||
native.PutUint32(b[4:8], uint32(msg.Index))
|
||||
native.PutUint32(b[8:12], msg.Flags)
|
||||
native.PutUint32(b[12:16], msg.Change)
|
||||
}
|
||||
|
||||
func (msg *IfInfomsg) serializeSafe() []byte {
|
||||
length := syscall.SizeofIfInfomsg
|
||||
b := make([]byte, length)
|
||||
msg.write(b)
|
||||
return b
|
||||
}
|
||||
|
||||
func deserializeIfInfomsgSafe(b []byte) *IfInfomsg {
|
||||
var msg = IfInfomsg{}
|
||||
binary.Read(bytes.NewReader(b[0:syscall.SizeofIfInfomsg]), NativeEndian(), &msg)
|
||||
return &msg
|
||||
}
|
||||
|
||||
func TestIfInfomsgDeserializeSerialize(t *testing.T) {
|
||||
var orig = make([]byte, syscall.SizeofIfInfomsg)
|
||||
rand.Read(orig)
|
||||
safemsg := deserializeIfInfomsgSafe(orig)
|
||||
msg := DeserializeIfInfomsg(orig)
|
||||
testDeserializeSerialize(t, orig, safemsg, msg)
|
||||
}
|
33
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/route_linux.go
generated
vendored
Normal file
33
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/route_linux.go
generated
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
package nl
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type RtMsg struct {
|
||||
syscall.RtMsg
|
||||
}
|
||||
|
||||
func NewRtMsg() *RtMsg {
|
||||
return &RtMsg{
|
||||
RtMsg: syscall.RtMsg{
|
||||
Table: syscall.RT_TABLE_MAIN,
|
||||
Scope: syscall.RT_SCOPE_UNIVERSE,
|
||||
Protocol: syscall.RTPROT_BOOT,
|
||||
Type: syscall.RTN_UNICAST,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (msg *RtMsg) Len() int {
|
||||
return syscall.SizeofRtMsg
|
||||
}
|
||||
|
||||
func DeserializeRtMsg(b []byte) *RtMsg {
|
||||
return (*RtMsg)(unsafe.Pointer(&b[0:syscall.SizeofRtMsg][0]))
|
||||
}
|
||||
|
||||
func (msg *RtMsg) Serialize() []byte {
|
||||
return (*(*[syscall.SizeofRtMsg]byte)(unsafe.Pointer(msg)))[:]
|
||||
}
|
43
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/route_linux_test.go
generated
vendored
Normal file
43
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/route_linux_test.go
generated
vendored
Normal file
|
@ -0,0 +1,43 @@
|
|||
package nl
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"syscall"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func (msg *RtMsg) write(b []byte) {
|
||||
native := NativeEndian()
|
||||
b[0] = msg.Family
|
||||
b[1] = msg.Dst_len
|
||||
b[2] = msg.Src_len
|
||||
b[3] = msg.Tos
|
||||
b[4] = msg.Table
|
||||
b[5] = msg.Protocol
|
||||
b[6] = msg.Scope
|
||||
b[7] = msg.Type
|
||||
native.PutUint32(b[8:12], msg.Flags)
|
||||
}
|
||||
|
||||
func (msg *RtMsg) serializeSafe() []byte {
|
||||
len := syscall.SizeofRtMsg
|
||||
b := make([]byte, len)
|
||||
msg.write(b)
|
||||
return b
|
||||
}
|
||||
|
||||
func deserializeRtMsgSafe(b []byte) *RtMsg {
|
||||
var msg = RtMsg{}
|
||||
binary.Read(bytes.NewReader(b[0:syscall.SizeofRtMsg]), NativeEndian(), &msg)
|
||||
return &msg
|
||||
}
|
||||
|
||||
func TestRtMsgDeserializeSerialize(t *testing.T) {
|
||||
var orig = make([]byte, syscall.SizeofRtMsg)
|
||||
rand.Read(orig)
|
||||
safemsg := deserializeRtMsgSafe(orig)
|
||||
msg := DeserializeRtMsg(orig)
|
||||
testDeserializeSerialize(t, orig, safemsg, msg)
|
||||
}
|
259
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/xfrm_linux.go
generated
vendored
Normal file
259
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/xfrm_linux.go
generated
vendored
Normal file
|
@ -0,0 +1,259 @@
|
|||
package nl
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Infinity for packet and byte counts
|
||||
const (
|
||||
XFRM_INF = ^uint64(0)
|
||||
)
|
||||
|
||||
// Message Types
|
||||
const (
|
||||
XFRM_MSG_BASE = 0x10
|
||||
XFRM_MSG_NEWSA = 0x10
|
||||
XFRM_MSG_DELSA = 0x11
|
||||
XFRM_MSG_GETSA = 0x12
|
||||
XFRM_MSG_NEWPOLICY = 0x13
|
||||
XFRM_MSG_DELPOLICY = 0x14
|
||||
XFRM_MSG_GETPOLICY = 0x15
|
||||
XFRM_MSG_ALLOCSPI = 0x16
|
||||
XFRM_MSG_ACQUIRE = 0x17
|
||||
XFRM_MSG_EXPIRE = 0x18
|
||||
XFRM_MSG_UPDPOLICY = 0x19
|
||||
XFRM_MSG_UPDSA = 0x1a
|
||||
XFRM_MSG_POLEXPIRE = 0x1b
|
||||
XFRM_MSG_FLUSHSA = 0x1c
|
||||
XFRM_MSG_FLUSHPOLICY = 0x1d
|
||||
XFRM_MSG_NEWAE = 0x1e
|
||||
XFRM_MSG_GETAE = 0x1f
|
||||
XFRM_MSG_REPORT = 0x20
|
||||
XFRM_MSG_MIGRATE = 0x21
|
||||
XFRM_MSG_NEWSADINFO = 0x22
|
||||
XFRM_MSG_GETSADINFO = 0x23
|
||||
XFRM_MSG_NEWSPDINFO = 0x24
|
||||
XFRM_MSG_GETSPDINFO = 0x25
|
||||
XFRM_MSG_MAPPING = 0x26
|
||||
XFRM_MSG_MAX = 0x26
|
||||
XFRM_NR_MSGTYPES = 0x17
|
||||
)
|
||||
|
||||
// Attribute types
|
||||
const (
|
||||
/* Netlink message attributes. */
|
||||
XFRMA_UNSPEC = 0x00
|
||||
XFRMA_ALG_AUTH = 0x01 /* struct xfrm_algo */
|
||||
XFRMA_ALG_CRYPT = 0x02 /* struct xfrm_algo */
|
||||
XFRMA_ALG_COMP = 0x03 /* struct xfrm_algo */
|
||||
XFRMA_ENCAP = 0x04 /* struct xfrm_algo + struct xfrm_encap_tmpl */
|
||||
XFRMA_TMPL = 0x05 /* 1 or more struct xfrm_user_tmpl */
|
||||
XFRMA_SA = 0x06 /* struct xfrm_usersa_info */
|
||||
XFRMA_POLICY = 0x07 /* struct xfrm_userpolicy_info */
|
||||
XFRMA_SEC_CTX = 0x08 /* struct xfrm_sec_ctx */
|
||||
XFRMA_LTIME_VAL = 0x09
|
||||
XFRMA_REPLAY_VAL = 0x0a
|
||||
XFRMA_REPLAY_THRESH = 0x0b
|
||||
XFRMA_ETIMER_THRESH = 0x0c
|
||||
XFRMA_SRCADDR = 0x0d /* xfrm_address_t */
|
||||
XFRMA_COADDR = 0x0e /* xfrm_address_t */
|
||||
XFRMA_LASTUSED = 0x0f /* unsigned long */
|
||||
XFRMA_POLICY_TYPE = 0x10 /* struct xfrm_userpolicy_type */
|
||||
XFRMA_MIGRATE = 0x11
|
||||
XFRMA_ALG_AEAD = 0x12 /* struct xfrm_algo_aead */
|
||||
XFRMA_KMADDRESS = 0x13 /* struct xfrm_user_kmaddress */
|
||||
XFRMA_ALG_AUTH_TRUNC = 0x14 /* struct xfrm_algo_auth */
|
||||
XFRMA_MARK = 0x15 /* struct xfrm_mark */
|
||||
XFRMA_TFCPAD = 0x16 /* __u32 */
|
||||
XFRMA_REPLAY_ESN_VAL = 0x17 /* struct xfrm_replay_esn */
|
||||
XFRMA_SA_EXTRA_FLAGS = 0x18 /* __u32 */
|
||||
XFRMA_MAX = 0x18
|
||||
)
|
||||
|
||||
const (
|
||||
SizeofXfrmAddress = 0x10
|
||||
SizeofXfrmSelector = 0x38
|
||||
SizeofXfrmLifetimeCfg = 0x40
|
||||
SizeofXfrmLifetimeCur = 0x20
|
||||
SizeofXfrmId = 0x18
|
||||
)
|
||||
|
||||
// typedef union {
|
||||
// __be32 a4;
|
||||
// __be32 a6[4];
|
||||
// } xfrm_address_t;
|
||||
|
||||
type XfrmAddress [SizeofXfrmAddress]byte
|
||||
|
||||
func (x *XfrmAddress) ToIP() net.IP {
|
||||
var empty = [12]byte{}
|
||||
ip := make(net.IP, net.IPv6len)
|
||||
if bytes.Equal(x[4:16], empty[:]) {
|
||||
ip[10] = 0xff
|
||||
ip[11] = 0xff
|
||||
copy(ip[12:16], x[0:4])
|
||||
} else {
|
||||
copy(ip[:], x[:])
|
||||
}
|
||||
return ip
|
||||
}
|
||||
|
||||
func (x *XfrmAddress) ToIPNet(prefixlen uint8) *net.IPNet {
|
||||
ip := x.ToIP()
|
||||
if GetIPFamily(ip) == FAMILY_V4 {
|
||||
return &net.IPNet{IP: ip, Mask: net.CIDRMask(int(prefixlen), 32)}
|
||||
} else {
|
||||
return &net.IPNet{IP: ip, Mask: net.CIDRMask(int(prefixlen), 128)}
|
||||
}
|
||||
}
|
||||
|
||||
func (x *XfrmAddress) FromIP(ip net.IP) {
|
||||
var empty = [16]byte{}
|
||||
if len(ip) < net.IPv4len {
|
||||
copy(x[4:16], empty[:])
|
||||
} else if GetIPFamily(ip) == FAMILY_V4 {
|
||||
copy(x[0:4], ip.To4()[0:4])
|
||||
copy(x[4:16], empty[:12])
|
||||
} else {
|
||||
copy(x[0:16], ip.To16()[0:16])
|
||||
}
|
||||
}
|
||||
|
||||
func DeserializeXfrmAddress(b []byte) *XfrmAddress {
|
||||
return (*XfrmAddress)(unsafe.Pointer(&b[0:SizeofXfrmAddress][0]))
|
||||
}
|
||||
|
||||
func (msg *XfrmAddress) Serialize() []byte {
|
||||
return (*(*[SizeofXfrmAddress]byte)(unsafe.Pointer(msg)))[:]
|
||||
}
|
||||
|
||||
// struct xfrm_selector {
|
||||
// xfrm_address_t daddr;
|
||||
// xfrm_address_t saddr;
|
||||
// __be16 dport;
|
||||
// __be16 dport_mask;
|
||||
// __be16 sport;
|
||||
// __be16 sport_mask;
|
||||
// __u16 family;
|
||||
// __u8 prefixlen_d;
|
||||
// __u8 prefixlen_s;
|
||||
// __u8 proto;
|
||||
// int ifindex;
|
||||
// __kernel_uid32_t user;
|
||||
// };
|
||||
|
||||
type XfrmSelector struct {
|
||||
Daddr XfrmAddress
|
||||
Saddr XfrmAddress
|
||||
Dport uint16 // big endian
|
||||
DportMask uint16 // big endian
|
||||
Sport uint16 // big endian
|
||||
SportMask uint16 // big endian
|
||||
Family uint16
|
||||
PrefixlenD uint8
|
||||
PrefixlenS uint8
|
||||
Proto uint8
|
||||
Pad [3]byte
|
||||
Ifindex int32
|
||||
User uint32
|
||||
}
|
||||
|
||||
func (msg *XfrmSelector) Len() int {
|
||||
return SizeofXfrmSelector
|
||||
}
|
||||
|
||||
func DeserializeXfrmSelector(b []byte) *XfrmSelector {
|
||||
return (*XfrmSelector)(unsafe.Pointer(&b[0:SizeofXfrmSelector][0]))
|
||||
}
|
||||
|
||||
func (msg *XfrmSelector) Serialize() []byte {
|
||||
return (*(*[SizeofXfrmSelector]byte)(unsafe.Pointer(msg)))[:]
|
||||
}
|
||||
|
||||
// struct xfrm_lifetime_cfg {
|
||||
// __u64 soft_byte_limit;
|
||||
// __u64 hard_byte_limit;
|
||||
// __u64 soft_packet_limit;
|
||||
// __u64 hard_packet_limit;
|
||||
// __u64 soft_add_expires_seconds;
|
||||
// __u64 hard_add_expires_seconds;
|
||||
// __u64 soft_use_expires_seconds;
|
||||
// __u64 hard_use_expires_seconds;
|
||||
// };
|
||||
//
|
||||
|
||||
type XfrmLifetimeCfg struct {
|
||||
SoftByteLimit uint64
|
||||
HardByteLimit uint64
|
||||
SoftPacketLimit uint64
|
||||
HardPacketLimit uint64
|
||||
SoftAddExpiresSeconds uint64
|
||||
HardAddExpiresSeconds uint64
|
||||
SoftUseExpiresSeconds uint64
|
||||
HardUseExpiresSeconds uint64
|
||||
}
|
||||
|
||||
func (msg *XfrmLifetimeCfg) Len() int {
|
||||
return SizeofXfrmLifetimeCfg
|
||||
}
|
||||
|
||||
func DeserializeXfrmLifetimeCfg(b []byte) *XfrmLifetimeCfg {
|
||||
return (*XfrmLifetimeCfg)(unsafe.Pointer(&b[0:SizeofXfrmLifetimeCfg][0]))
|
||||
}
|
||||
|
||||
func (msg *XfrmLifetimeCfg) Serialize() []byte {
|
||||
return (*(*[SizeofXfrmLifetimeCfg]byte)(unsafe.Pointer(msg)))[:]
|
||||
}
|
||||
|
||||
// struct xfrm_lifetime_cur {
|
||||
// __u64 bytes;
|
||||
// __u64 packets;
|
||||
// __u64 add_time;
|
||||
// __u64 use_time;
|
||||
// };
|
||||
|
||||
type XfrmLifetimeCur struct {
|
||||
Bytes uint64
|
||||
Packets uint64
|
||||
AddTime uint64
|
||||
UseTime uint64
|
||||
}
|
||||
|
||||
func (msg *XfrmLifetimeCur) Len() int {
|
||||
return SizeofXfrmLifetimeCur
|
||||
}
|
||||
|
||||
func DeserializeXfrmLifetimeCur(b []byte) *XfrmLifetimeCur {
|
||||
return (*XfrmLifetimeCur)(unsafe.Pointer(&b[0:SizeofXfrmLifetimeCur][0]))
|
||||
}
|
||||
|
||||
func (msg *XfrmLifetimeCur) Serialize() []byte {
|
||||
return (*(*[SizeofXfrmLifetimeCur]byte)(unsafe.Pointer(msg)))[:]
|
||||
}
|
||||
|
||||
// struct xfrm_id {
|
||||
// xfrm_address_t daddr;
|
||||
// __be32 spi;
|
||||
// __u8 proto;
|
||||
// };
|
||||
|
||||
type XfrmId struct {
|
||||
Daddr XfrmAddress
|
||||
Spi uint32 // big endian
|
||||
Proto uint8
|
||||
Pad [3]byte
|
||||
}
|
||||
|
||||
func (msg *XfrmId) Len() int {
|
||||
return SizeofXfrmId
|
||||
}
|
||||
|
||||
func DeserializeXfrmId(b []byte) *XfrmId {
|
||||
return (*XfrmId)(unsafe.Pointer(&b[0:SizeofXfrmId][0]))
|
||||
}
|
||||
|
||||
func (msg *XfrmId) Serialize() []byte {
|
||||
return (*(*[SizeofXfrmId]byte)(unsafe.Pointer(msg)))[:]
|
||||
}
|
161
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/xfrm_linux_test.go
generated
vendored
Normal file
161
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/xfrm_linux_test.go
generated
vendored
Normal file
|
@ -0,0 +1,161 @@
|
|||
package nl
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func (msg *XfrmAddress) write(b []byte) {
|
||||
copy(b[0:SizeofXfrmAddress], msg[:])
|
||||
}
|
||||
|
||||
func (msg *XfrmAddress) serializeSafe() []byte {
|
||||
b := make([]byte, SizeofXfrmAddress)
|
||||
msg.write(b)
|
||||
return b
|
||||
}
|
||||
|
||||
func deserializeXfrmAddressSafe(b []byte) *XfrmAddress {
|
||||
var msg = XfrmAddress{}
|
||||
binary.Read(bytes.NewReader(b[0:SizeofXfrmAddress]), NativeEndian(), &msg)
|
||||
return &msg
|
||||
}
|
||||
|
||||
func TestXfrmAddressDeserializeSerialize(t *testing.T) {
|
||||
var orig = make([]byte, SizeofXfrmAddress)
|
||||
rand.Read(orig)
|
||||
safemsg := deserializeXfrmAddressSafe(orig)
|
||||
msg := DeserializeXfrmAddress(orig)
|
||||
testDeserializeSerialize(t, orig, safemsg, msg)
|
||||
}
|
||||
|
||||
func (msg *XfrmSelector) write(b []byte) {
|
||||
const AddrEnd = SizeofXfrmAddress * 2
|
||||
native := NativeEndian()
|
||||
msg.Daddr.write(b[0:SizeofXfrmAddress])
|
||||
msg.Saddr.write(b[SizeofXfrmAddress:AddrEnd])
|
||||
native.PutUint16(b[AddrEnd:AddrEnd+2], msg.Dport)
|
||||
native.PutUint16(b[AddrEnd+2:AddrEnd+4], msg.DportMask)
|
||||
native.PutUint16(b[AddrEnd+4:AddrEnd+6], msg.Sport)
|
||||
native.PutUint16(b[AddrEnd+6:AddrEnd+8], msg.SportMask)
|
||||
native.PutUint16(b[AddrEnd+8:AddrEnd+10], msg.Family)
|
||||
b[AddrEnd+10] = msg.PrefixlenD
|
||||
b[AddrEnd+11] = msg.PrefixlenS
|
||||
b[AddrEnd+12] = msg.Proto
|
||||
copy(b[AddrEnd+13:AddrEnd+16], msg.Pad[:])
|
||||
native.PutUint32(b[AddrEnd+16:AddrEnd+20], uint32(msg.Ifindex))
|
||||
native.PutUint32(b[AddrEnd+20:AddrEnd+24], msg.User)
|
||||
}
|
||||
|
||||
func (msg *XfrmSelector) serializeSafe() []byte {
|
||||
length := SizeofXfrmSelector
|
||||
b := make([]byte, length)
|
||||
msg.write(b)
|
||||
return b
|
||||
}
|
||||
|
||||
func deserializeXfrmSelectorSafe(b []byte) *XfrmSelector {
|
||||
var msg = XfrmSelector{}
|
||||
binary.Read(bytes.NewReader(b[0:SizeofXfrmSelector]), NativeEndian(), &msg)
|
||||
return &msg
|
||||
}
|
||||
|
||||
func TestXfrmSelectorDeserializeSerialize(t *testing.T) {
|
||||
var orig = make([]byte, SizeofXfrmSelector)
|
||||
rand.Read(orig)
|
||||
safemsg := deserializeXfrmSelectorSafe(orig)
|
||||
msg := DeserializeXfrmSelector(orig)
|
||||
testDeserializeSerialize(t, orig, safemsg, msg)
|
||||
}
|
||||
|
||||
func (msg *XfrmLifetimeCfg) write(b []byte) {
|
||||
native := NativeEndian()
|
||||
native.PutUint64(b[0:8], msg.SoftByteLimit)
|
||||
native.PutUint64(b[8:16], msg.HardByteLimit)
|
||||
native.PutUint64(b[16:24], msg.SoftPacketLimit)
|
||||
native.PutUint64(b[24:32], msg.HardPacketLimit)
|
||||
native.PutUint64(b[32:40], msg.SoftAddExpiresSeconds)
|
||||
native.PutUint64(b[40:48], msg.HardAddExpiresSeconds)
|
||||
native.PutUint64(b[48:56], msg.SoftUseExpiresSeconds)
|
||||
native.PutUint64(b[56:64], msg.HardUseExpiresSeconds)
|
||||
}
|
||||
|
||||
func (msg *XfrmLifetimeCfg) serializeSafe() []byte {
|
||||
length := SizeofXfrmLifetimeCfg
|
||||
b := make([]byte, length)
|
||||
msg.write(b)
|
||||
return b
|
||||
}
|
||||
|
||||
func deserializeXfrmLifetimeCfgSafe(b []byte) *XfrmLifetimeCfg {
|
||||
var msg = XfrmLifetimeCfg{}
|
||||
binary.Read(bytes.NewReader(b[0:SizeofXfrmLifetimeCfg]), NativeEndian(), &msg)
|
||||
return &msg
|
||||
}
|
||||
|
||||
func TestXfrmLifetimeCfgDeserializeSerialize(t *testing.T) {
|
||||
var orig = make([]byte, SizeofXfrmLifetimeCfg)
|
||||
rand.Read(orig)
|
||||
safemsg := deserializeXfrmLifetimeCfgSafe(orig)
|
||||
msg := DeserializeXfrmLifetimeCfg(orig)
|
||||
testDeserializeSerialize(t, orig, safemsg, msg)
|
||||
}
|
||||
|
||||
func (msg *XfrmLifetimeCur) write(b []byte) {
|
||||
native := NativeEndian()
|
||||
native.PutUint64(b[0:8], msg.Bytes)
|
||||
native.PutUint64(b[8:16], msg.Packets)
|
||||
native.PutUint64(b[16:24], msg.AddTime)
|
||||
native.PutUint64(b[24:32], msg.UseTime)
|
||||
}
|
||||
|
||||
func (msg *XfrmLifetimeCur) serializeSafe() []byte {
|
||||
length := SizeofXfrmLifetimeCur
|
||||
b := make([]byte, length)
|
||||
msg.write(b)
|
||||
return b
|
||||
}
|
||||
|
||||
func deserializeXfrmLifetimeCurSafe(b []byte) *XfrmLifetimeCur {
|
||||
var msg = XfrmLifetimeCur{}
|
||||
binary.Read(bytes.NewReader(b[0:SizeofXfrmLifetimeCur]), NativeEndian(), &msg)
|
||||
return &msg
|
||||
}
|
||||
|
||||
func TestXfrmLifetimeCurDeserializeSerialize(t *testing.T) {
|
||||
var orig = make([]byte, SizeofXfrmLifetimeCur)
|
||||
rand.Read(orig)
|
||||
safemsg := deserializeXfrmLifetimeCurSafe(orig)
|
||||
msg := DeserializeXfrmLifetimeCur(orig)
|
||||
testDeserializeSerialize(t, orig, safemsg, msg)
|
||||
}
|
||||
|
||||
func (msg *XfrmId) write(b []byte) {
|
||||
native := NativeEndian()
|
||||
msg.Daddr.write(b[0:SizeofXfrmAddress])
|
||||
native.PutUint32(b[SizeofXfrmAddress:SizeofXfrmAddress+4], msg.Spi)
|
||||
b[SizeofXfrmAddress+4] = msg.Proto
|
||||
copy(b[SizeofXfrmAddress+5:SizeofXfrmAddress+8], msg.Pad[:])
|
||||
}
|
||||
|
||||
func (msg *XfrmId) serializeSafe() []byte {
|
||||
b := make([]byte, SizeofXfrmId)
|
||||
msg.write(b)
|
||||
return b
|
||||
}
|
||||
|
||||
func deserializeXfrmIdSafe(b []byte) *XfrmId {
|
||||
var msg = XfrmId{}
|
||||
binary.Read(bytes.NewReader(b[0:SizeofXfrmId]), NativeEndian(), &msg)
|
||||
return &msg
|
||||
}
|
||||
|
||||
func TestXfrmIdDeserializeSerialize(t *testing.T) {
|
||||
var orig = make([]byte, SizeofXfrmId)
|
||||
rand.Read(orig)
|
||||
safemsg := deserializeXfrmIdSafe(orig)
|
||||
msg := DeserializeXfrmId(orig)
|
||||
testDeserializeSerialize(t, orig, safemsg, msg)
|
||||
}
|
119
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/xfrm_policy_linux.go
generated
vendored
Normal file
119
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/xfrm_policy_linux.go
generated
vendored
Normal file
|
@ -0,0 +1,119 @@
|
|||
package nl
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
SizeofXfrmUserpolicyId = 0x40
|
||||
SizeofXfrmUserpolicyInfo = 0xa8
|
||||
SizeofXfrmUserTmpl = 0x40
|
||||
)
|
||||
|
||||
// struct xfrm_userpolicy_id {
|
||||
// struct xfrm_selector sel;
|
||||
// __u32 index;
|
||||
// __u8 dir;
|
||||
// };
|
||||
//
|
||||
|
||||
type XfrmUserpolicyId struct {
|
||||
Sel XfrmSelector
|
||||
Index uint32
|
||||
Dir uint8
|
||||
Pad [3]byte
|
||||
}
|
||||
|
||||
func (msg *XfrmUserpolicyId) Len() int {
|
||||
return SizeofXfrmUserpolicyId
|
||||
}
|
||||
|
||||
func DeserializeXfrmUserpolicyId(b []byte) *XfrmUserpolicyId {
|
||||
return (*XfrmUserpolicyId)(unsafe.Pointer(&b[0:SizeofXfrmUserpolicyId][0]))
|
||||
}
|
||||
|
||||
func (msg *XfrmUserpolicyId) Serialize() []byte {
|
||||
return (*(*[SizeofXfrmUserpolicyId]byte)(unsafe.Pointer(msg)))[:]
|
||||
}
|
||||
|
||||
// struct xfrm_userpolicy_info {
|
||||
// struct xfrm_selector sel;
|
||||
// struct xfrm_lifetime_cfg lft;
|
||||
// struct xfrm_lifetime_cur curlft;
|
||||
// __u32 priority;
|
||||
// __u32 index;
|
||||
// __u8 dir;
|
||||
// __u8 action;
|
||||
// #define XFRM_POLICY_ALLOW 0
|
||||
// #define XFRM_POLICY_BLOCK 1
|
||||
// __u8 flags;
|
||||
// #define XFRM_POLICY_LOCALOK 1 /* Allow user to override global policy */
|
||||
// /* Automatically expand selector to include matching ICMP payloads. */
|
||||
// #define XFRM_POLICY_ICMP 2
|
||||
// __u8 share;
|
||||
// };
|
||||
|
||||
type XfrmUserpolicyInfo struct {
|
||||
Sel XfrmSelector
|
||||
Lft XfrmLifetimeCfg
|
||||
Curlft XfrmLifetimeCur
|
||||
Priority uint32
|
||||
Index uint32
|
||||
Dir uint8
|
||||
Action uint8
|
||||
Flags uint8
|
||||
Share uint8
|
||||
Pad [4]byte
|
||||
}
|
||||
|
||||
func (msg *XfrmUserpolicyInfo) Len() int {
|
||||
return SizeofXfrmUserpolicyInfo
|
||||
}
|
||||
|
||||
func DeserializeXfrmUserpolicyInfo(b []byte) *XfrmUserpolicyInfo {
|
||||
return (*XfrmUserpolicyInfo)(unsafe.Pointer(&b[0:SizeofXfrmUserpolicyInfo][0]))
|
||||
}
|
||||
|
||||
func (msg *XfrmUserpolicyInfo) Serialize() []byte {
|
||||
return (*(*[SizeofXfrmUserpolicyInfo]byte)(unsafe.Pointer(msg)))[:]
|
||||
}
|
||||
|
||||
// struct xfrm_user_tmpl {
|
||||
// struct xfrm_id id;
|
||||
// __u16 family;
|
||||
// xfrm_address_t saddr;
|
||||
// __u32 reqid;
|
||||
// __u8 mode;
|
||||
// __u8 share;
|
||||
// __u8 optional;
|
||||
// __u32 aalgos;
|
||||
// __u32 ealgos;
|
||||
// __u32 calgos;
|
||||
// }
|
||||
|
||||
type XfrmUserTmpl struct {
|
||||
XfrmId XfrmId
|
||||
Family uint16
|
||||
Pad1 [2]byte
|
||||
Saddr XfrmAddress
|
||||
Reqid uint32
|
||||
Mode uint8
|
||||
Share uint8
|
||||
Optional uint8
|
||||
Pad2 byte
|
||||
Aalgos uint32
|
||||
Ealgos uint32
|
||||
Calgos uint32
|
||||
}
|
||||
|
||||
func (msg *XfrmUserTmpl) Len() int {
|
||||
return SizeofXfrmUserTmpl
|
||||
}
|
||||
|
||||
func DeserializeXfrmUserTmpl(b []byte) *XfrmUserTmpl {
|
||||
return (*XfrmUserTmpl)(unsafe.Pointer(&b[0:SizeofXfrmUserTmpl][0]))
|
||||
}
|
||||
|
||||
func (msg *XfrmUserTmpl) Serialize() []byte {
|
||||
return (*(*[SizeofXfrmUserTmpl]byte)(unsafe.Pointer(msg)))[:]
|
||||
}
|
109
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/xfrm_policy_linux_test.go
generated
vendored
Normal file
109
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/xfrm_policy_linux_test.go
generated
vendored
Normal file
|
@ -0,0 +1,109 @@
|
|||
package nl
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func (msg *XfrmUserpolicyId) write(b []byte) {
|
||||
native := NativeEndian()
|
||||
msg.Sel.write(b[0:SizeofXfrmSelector])
|
||||
native.PutUint32(b[SizeofXfrmSelector:SizeofXfrmSelector+4], msg.Index)
|
||||
b[SizeofXfrmSelector+4] = msg.Dir
|
||||
copy(b[SizeofXfrmSelector+5:SizeofXfrmSelector+8], msg.Pad[:])
|
||||
}
|
||||
|
||||
func (msg *XfrmUserpolicyId) serializeSafe() []byte {
|
||||
b := make([]byte, SizeofXfrmUserpolicyId)
|
||||
msg.write(b)
|
||||
return b
|
||||
}
|
||||
|
||||
func deserializeXfrmUserpolicyIdSafe(b []byte) *XfrmUserpolicyId {
|
||||
var msg = XfrmUserpolicyId{}
|
||||
binary.Read(bytes.NewReader(b[0:SizeofXfrmUserpolicyId]), NativeEndian(), &msg)
|
||||
return &msg
|
||||
}
|
||||
|
||||
func TestXfrmUserpolicyIdDeserializeSerialize(t *testing.T) {
|
||||
var orig = make([]byte, SizeofXfrmUserpolicyId)
|
||||
rand.Read(orig)
|
||||
safemsg := deserializeXfrmUserpolicyIdSafe(orig)
|
||||
msg := DeserializeXfrmUserpolicyId(orig)
|
||||
testDeserializeSerialize(t, orig, safemsg, msg)
|
||||
}
|
||||
|
||||
func (msg *XfrmUserpolicyInfo) write(b []byte) {
|
||||
const CfgEnd = SizeofXfrmSelector + SizeofXfrmLifetimeCfg
|
||||
const CurEnd = CfgEnd + SizeofXfrmLifetimeCur
|
||||
native := NativeEndian()
|
||||
msg.Sel.write(b[0:SizeofXfrmSelector])
|
||||
msg.Lft.write(b[SizeofXfrmSelector:CfgEnd])
|
||||
msg.Curlft.write(b[CfgEnd:CurEnd])
|
||||
native.PutUint32(b[CurEnd:CurEnd+4], msg.Priority)
|
||||
native.PutUint32(b[CurEnd+4:CurEnd+8], msg.Index)
|
||||
b[CurEnd+8] = msg.Dir
|
||||
b[CurEnd+9] = msg.Action
|
||||
b[CurEnd+10] = msg.Flags
|
||||
b[CurEnd+11] = msg.Share
|
||||
copy(b[CurEnd+12:CurEnd+16], msg.Pad[:])
|
||||
}
|
||||
|
||||
func (msg *XfrmUserpolicyInfo) serializeSafe() []byte {
|
||||
b := make([]byte, SizeofXfrmUserpolicyInfo)
|
||||
msg.write(b)
|
||||
return b
|
||||
}
|
||||
|
||||
func deserializeXfrmUserpolicyInfoSafe(b []byte) *XfrmUserpolicyInfo {
|
||||
var msg = XfrmUserpolicyInfo{}
|
||||
binary.Read(bytes.NewReader(b[0:SizeofXfrmUserpolicyInfo]), NativeEndian(), &msg)
|
||||
return &msg
|
||||
}
|
||||
|
||||
func TestXfrmUserpolicyInfoDeserializeSerialize(t *testing.T) {
|
||||
var orig = make([]byte, SizeofXfrmUserpolicyInfo)
|
||||
rand.Read(orig)
|
||||
safemsg := deserializeXfrmUserpolicyInfoSafe(orig)
|
||||
msg := DeserializeXfrmUserpolicyInfo(orig)
|
||||
testDeserializeSerialize(t, orig, safemsg, msg)
|
||||
}
|
||||
|
||||
func (msg *XfrmUserTmpl) write(b []byte) {
|
||||
const AddrEnd = SizeofXfrmId + 4 + SizeofXfrmAddress
|
||||
native := NativeEndian()
|
||||
msg.XfrmId.write(b[0:SizeofXfrmId])
|
||||
native.PutUint16(b[SizeofXfrmId:SizeofXfrmId+2], msg.Family)
|
||||
copy(b[SizeofXfrmId+2:SizeofXfrmId+4], msg.Pad1[:])
|
||||
msg.Saddr.write(b[SizeofXfrmId+4 : AddrEnd])
|
||||
native.PutUint32(b[AddrEnd:AddrEnd+4], msg.Reqid)
|
||||
b[AddrEnd+4] = msg.Mode
|
||||
b[AddrEnd+5] = msg.Share
|
||||
b[AddrEnd+6] = msg.Optional
|
||||
b[AddrEnd+7] = msg.Pad2
|
||||
native.PutUint32(b[AddrEnd+8:AddrEnd+12], msg.Aalgos)
|
||||
native.PutUint32(b[AddrEnd+12:AddrEnd+16], msg.Ealgos)
|
||||
native.PutUint32(b[AddrEnd+16:AddrEnd+20], msg.Calgos)
|
||||
}
|
||||
|
||||
func (msg *XfrmUserTmpl) serializeSafe() []byte {
|
||||
b := make([]byte, SizeofXfrmUserTmpl)
|
||||
msg.write(b)
|
||||
return b
|
||||
}
|
||||
|
||||
func deserializeXfrmUserTmplSafe(b []byte) *XfrmUserTmpl {
|
||||
var msg = XfrmUserTmpl{}
|
||||
binary.Read(bytes.NewReader(b[0:SizeofXfrmUserTmpl]), NativeEndian(), &msg)
|
||||
return &msg
|
||||
}
|
||||
|
||||
func TestXfrmUserTmplDeserializeSerialize(t *testing.T) {
|
||||
var orig = make([]byte, SizeofXfrmUserTmpl)
|
||||
rand.Read(orig)
|
||||
safemsg := deserializeXfrmUserTmplSafe(orig)
|
||||
msg := DeserializeXfrmUserTmpl(orig)
|
||||
testDeserializeSerialize(t, orig, safemsg, msg)
|
||||
}
|
221
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/xfrm_state_linux.go
generated
vendored
Normal file
221
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/xfrm_state_linux.go
generated
vendored
Normal file
|
@ -0,0 +1,221 @@
|
|||
package nl
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
SizeofXfrmUsersaId = 0x18
|
||||
SizeofXfrmStats = 0x0c
|
||||
SizeofXfrmUsersaInfo = 0xe0
|
||||
SizeofXfrmAlgo = 0x44
|
||||
SizeofXfrmAlgoAuth = 0x48
|
||||
SizeofXfrmEncapTmpl = 0x18
|
||||
)
|
||||
|
||||
// struct xfrm_usersa_id {
|
||||
// xfrm_address_t daddr;
|
||||
// __be32 spi;
|
||||
// __u16 family;
|
||||
// __u8 proto;
|
||||
// };
|
||||
|
||||
type XfrmUsersaId struct {
|
||||
Daddr XfrmAddress
|
||||
Spi uint32 // big endian
|
||||
Family uint16
|
||||
Proto uint8
|
||||
Pad byte
|
||||
}
|
||||
|
||||
func (msg *XfrmUsersaId) Len() int {
|
||||
return SizeofXfrmUsersaId
|
||||
}
|
||||
|
||||
func DeserializeXfrmUsersaId(b []byte) *XfrmUsersaId {
|
||||
return (*XfrmUsersaId)(unsafe.Pointer(&b[0:SizeofXfrmUsersaId][0]))
|
||||
}
|
||||
|
||||
func (msg *XfrmUsersaId) Serialize() []byte {
|
||||
return (*(*[SizeofXfrmUsersaId]byte)(unsafe.Pointer(msg)))[:]
|
||||
}
|
||||
|
||||
// struct xfrm_stats {
|
||||
// __u32 replay_window;
|
||||
// __u32 replay;
|
||||
// __u32 integrity_failed;
|
||||
// };
|
||||
|
||||
type XfrmStats struct {
|
||||
ReplayWindow uint32
|
||||
Replay uint32
|
||||
IntegrityFailed uint32
|
||||
}
|
||||
|
||||
func (msg *XfrmStats) Len() int {
|
||||
return SizeofXfrmStats
|
||||
}
|
||||
|
||||
func DeserializeXfrmStats(b []byte) *XfrmStats {
|
||||
return (*XfrmStats)(unsafe.Pointer(&b[0:SizeofXfrmStats][0]))
|
||||
}
|
||||
|
||||
func (msg *XfrmStats) Serialize() []byte {
|
||||
return (*(*[SizeofXfrmStats]byte)(unsafe.Pointer(msg)))[:]
|
||||
}
|
||||
|
||||
// struct xfrm_usersa_info {
|
||||
// struct xfrm_selector sel;
|
||||
// struct xfrm_id id;
|
||||
// xfrm_address_t saddr;
|
||||
// struct xfrm_lifetime_cfg lft;
|
||||
// struct xfrm_lifetime_cur curlft;
|
||||
// struct xfrm_stats stats;
|
||||
// __u32 seq;
|
||||
// __u32 reqid;
|
||||
// __u16 family;
|
||||
// __u8 mode; /* XFRM_MODE_xxx */
|
||||
// __u8 replay_window;
|
||||
// __u8 flags;
|
||||
// #define XFRM_STATE_NOECN 1
|
||||
// #define XFRM_STATE_DECAP_DSCP 2
|
||||
// #define XFRM_STATE_NOPMTUDISC 4
|
||||
// #define XFRM_STATE_WILDRECV 8
|
||||
// #define XFRM_STATE_ICMP 16
|
||||
// #define XFRM_STATE_AF_UNSPEC 32
|
||||
// #define XFRM_STATE_ALIGN4 64
|
||||
// #define XFRM_STATE_ESN 128
|
||||
// };
|
||||
//
|
||||
// #define XFRM_SA_XFLAG_DONT_ENCAP_DSCP 1
|
||||
//
|
||||
|
||||
type XfrmUsersaInfo struct {
|
||||
Sel XfrmSelector
|
||||
Id XfrmId
|
||||
Saddr XfrmAddress
|
||||
Lft XfrmLifetimeCfg
|
||||
Curlft XfrmLifetimeCur
|
||||
Stats XfrmStats
|
||||
Seq uint32
|
||||
Reqid uint32
|
||||
Family uint16
|
||||
Mode uint8
|
||||
ReplayWindow uint8
|
||||
Flags uint8
|
||||
Pad [7]byte
|
||||
}
|
||||
|
||||
func (msg *XfrmUsersaInfo) Len() int {
|
||||
return SizeofXfrmUsersaInfo
|
||||
}
|
||||
|
||||
func DeserializeXfrmUsersaInfo(b []byte) *XfrmUsersaInfo {
|
||||
return (*XfrmUsersaInfo)(unsafe.Pointer(&b[0:SizeofXfrmUsersaInfo][0]))
|
||||
}
|
||||
|
||||
func (msg *XfrmUsersaInfo) Serialize() []byte {
|
||||
return (*(*[SizeofXfrmUsersaInfo]byte)(unsafe.Pointer(msg)))[:]
|
||||
}
|
||||
|
||||
// struct xfrm_algo {
|
||||
// char alg_name[64];
|
||||
// unsigned int alg_key_len; /* in bits */
|
||||
// char alg_key[0];
|
||||
// };
|
||||
|
||||
type XfrmAlgo struct {
|
||||
AlgName [64]byte
|
||||
AlgKeyLen uint32
|
||||
AlgKey []byte
|
||||
}
|
||||
|
||||
func (msg *XfrmAlgo) Len() int {
|
||||
return SizeofXfrmAlgo + int(msg.AlgKeyLen/8)
|
||||
}
|
||||
|
||||
func DeserializeXfrmAlgo(b []byte) *XfrmAlgo {
|
||||
ret := XfrmAlgo{}
|
||||
copy(ret.AlgName[:], b[0:64])
|
||||
ret.AlgKeyLen = *(*uint32)(unsafe.Pointer(&b[64]))
|
||||
ret.AlgKey = b[68:ret.Len()]
|
||||
return &ret
|
||||
}
|
||||
|
||||
func (msg *XfrmAlgo) Serialize() []byte {
|
||||
b := make([]byte, msg.Len())
|
||||
copy(b[0:64], msg.AlgName[:])
|
||||
copy(b[64:68], (*(*[4]byte)(unsafe.Pointer(&msg.AlgKeyLen)))[:])
|
||||
copy(b[68:msg.Len()], msg.AlgKey[:])
|
||||
return b
|
||||
}
|
||||
|
||||
// struct xfrm_algo_auth {
|
||||
// char alg_name[64];
|
||||
// unsigned int alg_key_len; /* in bits */
|
||||
// unsigned int alg_trunc_len; /* in bits */
|
||||
// char alg_key[0];
|
||||
// };
|
||||
|
||||
type XfrmAlgoAuth struct {
|
||||
AlgName [64]byte
|
||||
AlgKeyLen uint32
|
||||
AlgTruncLen uint32
|
||||
AlgKey []byte
|
||||
}
|
||||
|
||||
func (msg *XfrmAlgoAuth) Len() int {
|
||||
return SizeofXfrmAlgoAuth + int(msg.AlgKeyLen/8)
|
||||
}
|
||||
|
||||
func DeserializeXfrmAlgoAuth(b []byte) *XfrmAlgoAuth {
|
||||
ret := XfrmAlgoAuth{}
|
||||
copy(ret.AlgName[:], b[0:64])
|
||||
ret.AlgKeyLen = *(*uint32)(unsafe.Pointer(&b[64]))
|
||||
ret.AlgTruncLen = *(*uint32)(unsafe.Pointer(&b[68]))
|
||||
ret.AlgKey = b[72:ret.Len()]
|
||||
return &ret
|
||||
}
|
||||
|
||||
func (msg *XfrmAlgoAuth) Serialize() []byte {
|
||||
b := make([]byte, msg.Len())
|
||||
copy(b[0:64], msg.AlgName[:])
|
||||
copy(b[64:68], (*(*[4]byte)(unsafe.Pointer(&msg.AlgKeyLen)))[:])
|
||||
copy(b[68:72], (*(*[4]byte)(unsafe.Pointer(&msg.AlgTruncLen)))[:])
|
||||
copy(b[72:msg.Len()], msg.AlgKey[:])
|
||||
return b
|
||||
}
|
||||
|
||||
// struct xfrm_algo_aead {
|
||||
// char alg_name[64];
|
||||
// unsigned int alg_key_len; /* in bits */
|
||||
// unsigned int alg_icv_len; /* in bits */
|
||||
// char alg_key[0];
|
||||
// }
|
||||
|
||||
// struct xfrm_encap_tmpl {
|
||||
// __u16 encap_type;
|
||||
// __be16 encap_sport;
|
||||
// __be16 encap_dport;
|
||||
// xfrm_address_t encap_oa;
|
||||
// };
|
||||
|
||||
type XfrmEncapTmpl struct {
|
||||
EncapType uint16
|
||||
EncapSport uint16 // big endian
|
||||
EncapDport uint16 // big endian
|
||||
Pad [2]byte
|
||||
EncapOa XfrmAddress
|
||||
}
|
||||
|
||||
func (msg *XfrmEncapTmpl) Len() int {
|
||||
return SizeofXfrmEncapTmpl
|
||||
}
|
||||
|
||||
func DeserializeXfrmEncapTmpl(b []byte) *XfrmEncapTmpl {
|
||||
return (*XfrmEncapTmpl)(unsafe.Pointer(&b[0:SizeofXfrmEncapTmpl][0]))
|
||||
}
|
||||
|
||||
func (msg *XfrmEncapTmpl) Serialize() []byte {
|
||||
return (*(*[SizeofXfrmEncapTmpl]byte)(unsafe.Pointer(msg)))[:]
|
||||
}
|
207
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/xfrm_state_linux_test.go
generated
vendored
Normal file
207
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/xfrm_state_linux_test.go
generated
vendored
Normal file
|
@ -0,0 +1,207 @@
|
|||
package nl
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func (msg *XfrmUsersaId) write(b []byte) {
|
||||
native := NativeEndian()
|
||||
msg.Daddr.write(b[0:SizeofXfrmAddress])
|
||||
native.PutUint32(b[SizeofXfrmAddress:SizeofXfrmAddress+4], msg.Spi)
|
||||
native.PutUint16(b[SizeofXfrmAddress+4:SizeofXfrmAddress+6], msg.Family)
|
||||
b[SizeofXfrmAddress+6] = msg.Proto
|
||||
b[SizeofXfrmAddress+7] = msg.Pad
|
||||
}
|
||||
|
||||
func (msg *XfrmUsersaId) serializeSafe() []byte {
|
||||
b := make([]byte, SizeofXfrmUsersaId)
|
||||
msg.write(b)
|
||||
return b
|
||||
}
|
||||
|
||||
func deserializeXfrmUsersaIdSafe(b []byte) *XfrmUsersaId {
|
||||
var msg = XfrmUsersaId{}
|
||||
binary.Read(bytes.NewReader(b[0:SizeofXfrmUsersaId]), NativeEndian(), &msg)
|
||||
return &msg
|
||||
}
|
||||
|
||||
func TestXfrmUsersaIdDeserializeSerialize(t *testing.T) {
|
||||
var orig = make([]byte, SizeofXfrmUsersaId)
|
||||
rand.Read(orig)
|
||||
safemsg := deserializeXfrmUsersaIdSafe(orig)
|
||||
msg := DeserializeXfrmUsersaId(orig)
|
||||
testDeserializeSerialize(t, orig, safemsg, msg)
|
||||
}
|
||||
|
||||
func (msg *XfrmStats) write(b []byte) {
|
||||
native := NativeEndian()
|
||||
native.PutUint32(b[0:4], msg.ReplayWindow)
|
||||
native.PutUint32(b[4:8], msg.Replay)
|
||||
native.PutUint32(b[8:12], msg.IntegrityFailed)
|
||||
}
|
||||
|
||||
func (msg *XfrmStats) serializeSafe() []byte {
|
||||
b := make([]byte, SizeofXfrmStats)
|
||||
msg.write(b)
|
||||
return b
|
||||
}
|
||||
|
||||
func deserializeXfrmStatsSafe(b []byte) *XfrmStats {
|
||||
var msg = XfrmStats{}
|
||||
binary.Read(bytes.NewReader(b[0:SizeofXfrmStats]), NativeEndian(), &msg)
|
||||
return &msg
|
||||
}
|
||||
|
||||
func TestXfrmStatsDeserializeSerialize(t *testing.T) {
|
||||
var orig = make([]byte, SizeofXfrmStats)
|
||||
rand.Read(orig)
|
||||
safemsg := deserializeXfrmStatsSafe(orig)
|
||||
msg := DeserializeXfrmStats(orig)
|
||||
testDeserializeSerialize(t, orig, safemsg, msg)
|
||||
}
|
||||
|
||||
func (msg *XfrmUsersaInfo) write(b []byte) {
|
||||
const IdEnd = SizeofXfrmSelector + SizeofXfrmId
|
||||
const AddressEnd = IdEnd + SizeofXfrmAddress
|
||||
const CfgEnd = AddressEnd + SizeofXfrmLifetimeCfg
|
||||
const CurEnd = CfgEnd + SizeofXfrmLifetimeCur
|
||||
const StatsEnd = CurEnd + SizeofXfrmStats
|
||||
native := NativeEndian()
|
||||
msg.Sel.write(b[0:SizeofXfrmSelector])
|
||||
msg.Id.write(b[SizeofXfrmSelector:IdEnd])
|
||||
msg.Saddr.write(b[IdEnd:AddressEnd])
|
||||
msg.Lft.write(b[AddressEnd:CfgEnd])
|
||||
msg.Curlft.write(b[CfgEnd:CurEnd])
|
||||
msg.Stats.write(b[CurEnd:StatsEnd])
|
||||
native.PutUint32(b[StatsEnd:StatsEnd+4], msg.Seq)
|
||||
native.PutUint32(b[StatsEnd+4:StatsEnd+8], msg.Reqid)
|
||||
native.PutUint16(b[StatsEnd+8:StatsEnd+10], msg.Family)
|
||||
b[StatsEnd+10] = msg.Mode
|
||||
b[StatsEnd+11] = msg.ReplayWindow
|
||||
b[StatsEnd+12] = msg.Flags
|
||||
copy(b[StatsEnd+13:StatsEnd+20], msg.Pad[:])
|
||||
}
|
||||
|
||||
func (msg *XfrmUsersaInfo) serializeSafe() []byte {
|
||||
b := make([]byte, SizeofXfrmUsersaInfo)
|
||||
msg.write(b)
|
||||
return b
|
||||
}
|
||||
|
||||
func deserializeXfrmUsersaInfoSafe(b []byte) *XfrmUsersaInfo {
|
||||
var msg = XfrmUsersaInfo{}
|
||||
binary.Read(bytes.NewReader(b[0:SizeofXfrmUsersaInfo]), NativeEndian(), &msg)
|
||||
return &msg
|
||||
}
|
||||
|
||||
func TestXfrmUsersaInfoDeserializeSerialize(t *testing.T) {
|
||||
var orig = make([]byte, SizeofXfrmUsersaInfo)
|
||||
rand.Read(orig)
|
||||
safemsg := deserializeXfrmUsersaInfoSafe(orig)
|
||||
msg := DeserializeXfrmUsersaInfo(orig)
|
||||
testDeserializeSerialize(t, orig, safemsg, msg)
|
||||
}
|
||||
|
||||
func (msg *XfrmAlgo) write(b []byte) {
|
||||
native := NativeEndian()
|
||||
copy(b[0:64], msg.AlgName[:])
|
||||
native.PutUint32(b[64:68], msg.AlgKeyLen)
|
||||
copy(b[68:msg.Len()], msg.AlgKey[:])
|
||||
}
|
||||
|
||||
func (msg *XfrmAlgo) serializeSafe() []byte {
|
||||
b := make([]byte, msg.Len())
|
||||
msg.write(b)
|
||||
return b
|
||||
}
|
||||
|
||||
func deserializeXfrmAlgoSafe(b []byte) *XfrmAlgo {
|
||||
var msg = XfrmAlgo{}
|
||||
copy(msg.AlgName[:], b[0:64])
|
||||
binary.Read(bytes.NewReader(b[64:68]), NativeEndian(), &msg.AlgKeyLen)
|
||||
msg.AlgKey = b[68:msg.Len()]
|
||||
return &msg
|
||||
}
|
||||
|
||||
func TestXfrmAlgoDeserializeSerialize(t *testing.T) {
|
||||
// use a 32 byte key len
|
||||
var orig = make([]byte, SizeofXfrmAlgo+32)
|
||||
rand.Read(orig)
|
||||
// set the key len to 256 bits
|
||||
orig[64] = 0
|
||||
orig[65] = 1
|
||||
orig[66] = 0
|
||||
orig[67] = 0
|
||||
safemsg := deserializeXfrmAlgoSafe(orig)
|
||||
msg := DeserializeXfrmAlgo(orig)
|
||||
testDeserializeSerialize(t, orig, safemsg, msg)
|
||||
}
|
||||
|
||||
func (msg *XfrmAlgoAuth) write(b []byte) {
|
||||
native := NativeEndian()
|
||||
copy(b[0:64], msg.AlgName[:])
|
||||
native.PutUint32(b[64:68], msg.AlgKeyLen)
|
||||
native.PutUint32(b[68:72], msg.AlgTruncLen)
|
||||
copy(b[72:msg.Len()], msg.AlgKey[:])
|
||||
}
|
||||
|
||||
func (msg *XfrmAlgoAuth) serializeSafe() []byte {
|
||||
b := make([]byte, msg.Len())
|
||||
msg.write(b)
|
||||
return b
|
||||
}
|
||||
|
||||
func deserializeXfrmAlgoAuthSafe(b []byte) *XfrmAlgoAuth {
|
||||
var msg = XfrmAlgoAuth{}
|
||||
copy(msg.AlgName[:], b[0:64])
|
||||
binary.Read(bytes.NewReader(b[64:68]), NativeEndian(), &msg.AlgKeyLen)
|
||||
binary.Read(bytes.NewReader(b[68:72]), NativeEndian(), &msg.AlgTruncLen)
|
||||
msg.AlgKey = b[72:msg.Len()]
|
||||
return &msg
|
||||
}
|
||||
|
||||
func TestXfrmAlgoAuthDeserializeSerialize(t *testing.T) {
|
||||
// use a 32 byte key len
|
||||
var orig = make([]byte, SizeofXfrmAlgoAuth+32)
|
||||
rand.Read(orig)
|
||||
// set the key len to 256 bits
|
||||
orig[64] = 0
|
||||
orig[65] = 1
|
||||
orig[66] = 0
|
||||
orig[67] = 0
|
||||
safemsg := deserializeXfrmAlgoAuthSafe(orig)
|
||||
msg := DeserializeXfrmAlgoAuth(orig)
|
||||
testDeserializeSerialize(t, orig, safemsg, msg)
|
||||
}
|
||||
|
||||
func (msg *XfrmEncapTmpl) write(b []byte) {
|
||||
native := NativeEndian()
|
||||
native.PutUint16(b[0:2], msg.EncapType)
|
||||
native.PutUint16(b[2:4], msg.EncapSport)
|
||||
native.PutUint16(b[4:6], msg.EncapDport)
|
||||
copy(b[6:8], msg.Pad[:])
|
||||
msg.EncapOa.write(b[8:SizeofXfrmAddress])
|
||||
}
|
||||
|
||||
func (msg *XfrmEncapTmpl) serializeSafe() []byte {
|
||||
b := make([]byte, SizeofXfrmEncapTmpl)
|
||||
msg.write(b)
|
||||
return b
|
||||
}
|
||||
|
||||
func deserializeXfrmEncapTmplSafe(b []byte) *XfrmEncapTmpl {
|
||||
var msg = XfrmEncapTmpl{}
|
||||
binary.Read(bytes.NewReader(b[0:SizeofXfrmEncapTmpl]), NativeEndian(), &msg)
|
||||
return &msg
|
||||
}
|
||||
|
||||
func TestXfrmEncapTmplDeserializeSerialize(t *testing.T) {
|
||||
var orig = make([]byte, SizeofXfrmEncapTmpl)
|
||||
rand.Read(orig)
|
||||
safemsg := deserializeXfrmEncapTmplSafe(orig)
|
||||
msg := DeserializeXfrmEncapTmpl(orig)
|
||||
testDeserializeSerialize(t, orig, safemsg, msg)
|
||||
}
|
53
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/protinfo.go
generated
vendored
Normal file
53
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/protinfo.go
generated
vendored
Normal file
|
@ -0,0 +1,53 @@
|
|||
package netlink
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Protinfo represents bridge flags from netlink.
|
||||
type Protinfo struct {
|
||||
Hairpin bool
|
||||
Guard bool
|
||||
FastLeave bool
|
||||
RootBlock bool
|
||||
Learning bool
|
||||
Flood bool
|
||||
}
|
||||
|
||||
// String returns a list of enabled flags
|
||||
func (prot *Protinfo) String() string {
|
||||
boolStrings := make([]string, 0)
|
||||
if prot.Hairpin {
|
||||
boolStrings = append(boolStrings, "Hairpin")
|
||||
}
|
||||
if prot.Guard {
|
||||
boolStrings = append(boolStrings, "Guard")
|
||||
}
|
||||
if prot.FastLeave {
|
||||
boolStrings = append(boolStrings, "FastLeave")
|
||||
}
|
||||
if prot.RootBlock {
|
||||
boolStrings = append(boolStrings, "RootBlock")
|
||||
}
|
||||
if prot.Learning {
|
||||
boolStrings = append(boolStrings, "Learning")
|
||||
}
|
||||
if prot.Flood {
|
||||
boolStrings = append(boolStrings, "Flood")
|
||||
}
|
||||
return strings.Join(boolStrings, " ")
|
||||
}
|
||||
|
||||
func boolToByte(x bool) []byte {
|
||||
if x {
|
||||
return []byte{1}
|
||||
}
|
||||
return []byte{0}
|
||||
}
|
||||
|
||||
func byteToBool(x byte) bool {
|
||||
if uint8(x) != 0 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
60
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/protinfo_linux.go
generated
vendored
Normal file
60
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/protinfo_linux.go
generated
vendored
Normal file
|
@ -0,0 +1,60 @@
|
|||
package netlink
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"syscall"
|
||||
|
||||
"github.com/vishvananda/netlink/nl"
|
||||
)
|
||||
|
||||
func LinkGetProtinfo(link Link) (Protinfo, error) {
|
||||
base := link.Attrs()
|
||||
ensureIndex(base)
|
||||
var pi Protinfo
|
||||
req := nl.NewNetlinkRequest(syscall.RTM_GETLINK, syscall.NLM_F_DUMP)
|
||||
msg := nl.NewIfInfomsg(syscall.AF_BRIDGE)
|
||||
req.AddData(msg)
|
||||
msgs, err := req.Execute(syscall.NETLINK_ROUTE, 0)
|
||||
if err != nil {
|
||||
return pi, err
|
||||
}
|
||||
|
||||
for _, m := range msgs {
|
||||
ans := nl.DeserializeIfInfomsg(m)
|
||||
if int(ans.Index) != base.Index {
|
||||
continue
|
||||
}
|
||||
attrs, err := nl.ParseRouteAttr(m[ans.Len():])
|
||||
if err != nil {
|
||||
return pi, err
|
||||
}
|
||||
for _, attr := range attrs {
|
||||
if attr.Attr.Type != syscall.IFLA_PROTINFO|syscall.NLA_F_NESTED {
|
||||
continue
|
||||
}
|
||||
infos, err := nl.ParseRouteAttr(attr.Value)
|
||||
if err != nil {
|
||||
return pi, err
|
||||
}
|
||||
var pi Protinfo
|
||||
for _, info := range infos {
|
||||
switch info.Attr.Type {
|
||||
case nl.IFLA_BRPORT_MODE:
|
||||
pi.Hairpin = byteToBool(info.Value[0])
|
||||
case nl.IFLA_BRPORT_GUARD:
|
||||
pi.Guard = byteToBool(info.Value[0])
|
||||
case nl.IFLA_BRPORT_FAST_LEAVE:
|
||||
pi.FastLeave = byteToBool(info.Value[0])
|
||||
case nl.IFLA_BRPORT_PROTECT:
|
||||
pi.RootBlock = byteToBool(info.Value[0])
|
||||
case nl.IFLA_BRPORT_LEARNING:
|
||||
pi.Learning = byteToBool(info.Value[0])
|
||||
case nl.IFLA_BRPORT_UNICAST_FLOOD:
|
||||
pi.Flood = byteToBool(info.Value[0])
|
||||
}
|
||||
}
|
||||
return pi, nil
|
||||
}
|
||||
}
|
||||
return pi, fmt.Errorf("Device with index %d not found", base.Index)
|
||||
}
|
98
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/protinfo_test.go
generated
vendored
Normal file
98
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/protinfo_test.go
generated
vendored
Normal file
|
@ -0,0 +1,98 @@
|
|||
package netlink
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestProtinfo(t *testing.T) {
|
||||
tearDown := setUpNetlinkTest(t)
|
||||
defer tearDown()
|
||||
master := &Bridge{LinkAttrs{Name: "foo"}}
|
||||
if err := LinkAdd(master); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
iface1 := &Dummy{LinkAttrs{Name: "bar1", MasterIndex: master.Index}}
|
||||
iface2 := &Dummy{LinkAttrs{Name: "bar2", MasterIndex: master.Index}}
|
||||
iface3 := &Dummy{LinkAttrs{Name: "bar3"}}
|
||||
|
||||
if err := LinkAdd(iface1); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := LinkAdd(iface2); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := LinkAdd(iface3); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
oldpi1, err := LinkGetProtinfo(iface1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
oldpi2, err := LinkGetProtinfo(iface2)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := LinkSetHairpin(iface1, true); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := LinkSetRootBlock(iface1, true); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
pi1, err := LinkGetProtinfo(iface1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !pi1.Hairpin {
|
||||
t.Fatalf("Hairpin mode is not enabled for %s, but should", iface1.Name)
|
||||
}
|
||||
if !pi1.RootBlock {
|
||||
t.Fatalf("RootBlock is not enabled for %s, but should", iface1.Name)
|
||||
}
|
||||
if pi1.Guard != oldpi1.Guard {
|
||||
t.Fatalf("Guard field was changed for %s but shouldn't", iface1.Name)
|
||||
}
|
||||
if pi1.FastLeave != oldpi1.FastLeave {
|
||||
t.Fatalf("FastLeave field was changed for %s but shouldn't", iface1.Name)
|
||||
}
|
||||
if pi1.Learning != oldpi1.Learning {
|
||||
t.Fatalf("Learning field was changed for %s but shouldn't", iface1.Name)
|
||||
}
|
||||
if pi1.Flood != oldpi1.Flood {
|
||||
t.Fatalf("Flood field was changed for %s but shouldn't", iface1.Name)
|
||||
}
|
||||
|
||||
if err := LinkSetGuard(iface2, true); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := LinkSetLearning(iface2, false); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
pi2, err := LinkGetProtinfo(iface2)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if pi2.Hairpin {
|
||||
t.Fatalf("Hairpin mode is enabled for %s, but shouldn't", iface2.Name)
|
||||
}
|
||||
if !pi2.Guard {
|
||||
t.Fatalf("Guard is not enabled for %s, but should", iface2.Name)
|
||||
}
|
||||
if pi2.Learning {
|
||||
t.Fatalf("Learning is enabled for %s, but shouldn't", iface2.Name)
|
||||
}
|
||||
if pi2.RootBlock != oldpi2.RootBlock {
|
||||
t.Fatalf("RootBlock field was changed for %s but shouldn't", iface2.Name)
|
||||
}
|
||||
if pi2.FastLeave != oldpi2.FastLeave {
|
||||
t.Fatalf("FastLeave field was changed for %s but shouldn't", iface2.Name)
|
||||
}
|
||||
if pi2.Flood != oldpi2.Flood {
|
||||
t.Fatalf("Flood field was changed for %s but shouldn't", iface2.Name)
|
||||
}
|
||||
|
||||
if err := LinkSetHairpin(iface3, true); err == nil || err.Error() != "operation not supported" {
|
||||
t.Fatalf("Set protinfo attrs for link without master is not supported, but err: %s", err)
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue