From 58b8b8fa1555223c1144f08fc4536ffaa4d12fd0 Mon Sep 17 00:00:00 2001 From: Alessandro Boch Date: Wed, 22 Jun 2016 09:31:55 -0700 Subject: [PATCH 1/3] Vendoring vishvananda/netlink 734d02c Signed-off-by: Alessandro Boch --- hack/vendor.sh | 2 +- .../github.com/vishvananda/netlink/README.md | 2 +- .../github.com/vishvananda/netlink/class.go | 33 ------- .../vishvananda/netlink/class_linux.go | 34 +++++++ .../github.com/vishvananda/netlink/filter.go | 75 +-------------- .../vishvananda/netlink/filter_linux.go | 75 ++++++++++++++- .../github.com/vishvananda/netlink/handle.go | 86 ----------------- .../vishvananda/netlink/handle_linux.go | 86 +++++++++++++++++ .../github.com/vishvananda/netlink/link.go | 6 -- .../vishvananda/netlink/link_linux.go | 10 ++ .../github.com/vishvananda/netlink/netlink.go | 13 +-- .../vishvananda/netlink/netlink_linux.go | 10 ++ .../netlink/netlink_unspecified.go | 4 +- .../vishvananda/netlink/nl/nl_linux.go | 37 +++++--- .../vishvananda/netlink/nl/route_linux.go | 12 +++ .../github.com/vishvananda/netlink/qdisc.go | 64 ------------- .../vishvananda/netlink/qdisc_linux.go | 65 +++++++++++++ .../github.com/vishvananda/netlink/route.go | 44 +++------ .../vishvananda/netlink/route_linux.go | 93 +++++++++++++++++++ .../vishvananda/netlink/route_unspecified.go | 7 ++ .../github.com/vishvananda/netlink/rule.go | 3 - .../vishvananda/netlink/rule_linux.go | 1 - .../github.com/vishvananda/netlink/xfrm.go | 2 +- .../vishvananda/netlink/xfrm_state.go | 4 +- 24 files changed, 438 insertions(+), 330 deletions(-) delete mode 100644 vendor/src/github.com/vishvananda/netlink/handle.go create mode 100644 vendor/src/github.com/vishvananda/netlink/handle_linux.go create mode 100644 vendor/src/github.com/vishvananda/netlink/netlink_linux.go create mode 100644 vendor/src/github.com/vishvananda/netlink/route_unspecified.go diff --git a/hack/vendor.sh b/hack/vendor.sh index 49132999b3..1f16ff58a1 100755 --- a/hack/vendor.sh +++ b/hack/vendor.sh @@ -75,7 +75,7 @@ clone git github.com/hashicorp/go-multierror fcdddc395df1ddf4247c69bd436e84cfa07 clone git github.com/hashicorp/serf 598c54895cc5a7b1a24a398d635e8c0ea0959870 clone git github.com/docker/libkv 7283ef27ed32fe267388510a91709b307bb9942c clone git github.com/vishvananda/netns 604eaf189ee867d8c147fafc28def2394e878d25 -clone git github.com/vishvananda/netlink 7995ff5647a22cbf0dc41bf5c0e977bdb0d5c6b7 +clone git github.com/vishvananda/netlink 734d02c3e202f682c74b71314b2c61eec0170fd4 clone git github.com/BurntSushi/toml f706d00e3de6abe700c994cdd545a1a4915af060 clone git github.com/samuel/go-zookeeper d0e0d8e11f318e000a8cc434616d69e329edc374 clone git github.com/deckarep/golang-set ef32fa3046d9f249d399f98ebaf9be944430fd1d diff --git a/vendor/src/github.com/vishvananda/netlink/README.md b/vendor/src/github.com/vishvananda/netlink/README.md index 8cd50a93b6..2367fae097 100644 --- a/vendor/src/github.com/vishvananda/netlink/README.md +++ b/vendor/src/github.com/vishvananda/netlink/README.md @@ -8,7 +8,7 @@ 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. +to provide an api that is loosely modeled on the CLI provided 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 diff --git a/vendor/src/github.com/vishvananda/netlink/class.go b/vendor/src/github.com/vishvananda/netlink/class.go index 4577304100..8ee13af48e 100644 --- a/vendor/src/github.com/vishvananda/netlink/class.go +++ b/vendor/src/github.com/vishvananda/netlink/class.go @@ -50,39 +50,6 @@ type HtbClass struct { Prio uint32 } -func NewHtbClass(attrs ClassAttrs, cattrs HtbClassAttrs) *HtbClass { - mtu := 1600 - rate := cattrs.Rate / 8 - ceil := cattrs.Ceil / 8 - buffer := cattrs.Buffer - cbuffer := cattrs.Cbuffer - - if ceil == 0 { - ceil = rate - } - - if buffer == 0 { - buffer = uint32(float64(rate)/Hz() + float64(mtu)) - } - buffer = uint32(Xmittime(rate, buffer)) - - if cbuffer == 0 { - cbuffer = uint32(float64(ceil)/Hz() + float64(mtu)) - } - cbuffer = uint32(Xmittime(ceil, cbuffer)) - - return &HtbClass{ - ClassAttrs: attrs, - Rate: rate, - Ceil: ceil, - Buffer: buffer, - Cbuffer: cbuffer, - Quantum: 10, - Level: 0, - Prio: 0, - } -} - func (q HtbClass) String() string { return fmt.Sprintf("{Rate: %d, Ceil: %d, Buffer: %d, Cbuffer: %d}", q.Rate, q.Ceil, q.Buffer, q.Cbuffer) } diff --git a/vendor/src/github.com/vishvananda/netlink/class_linux.go b/vendor/src/github.com/vishvananda/netlink/class_linux.go index be62abd9cb..91cd3883de 100644 --- a/vendor/src/github.com/vishvananda/netlink/class_linux.go +++ b/vendor/src/github.com/vishvananda/netlink/class_linux.go @@ -7,6 +7,40 @@ import ( "github.com/vishvananda/netlink/nl" ) +// NOTE: function is in here because it uses other linux functions +func NewHtbClass(attrs ClassAttrs, cattrs HtbClassAttrs) *HtbClass { + mtu := 1600 + rate := cattrs.Rate / 8 + ceil := cattrs.Ceil / 8 + buffer := cattrs.Buffer + cbuffer := cattrs.Cbuffer + + if ceil == 0 { + ceil = rate + } + + if buffer == 0 { + buffer = uint32(float64(rate)/Hz() + float64(mtu)) + } + buffer = uint32(Xmittime(rate, buffer)) + + if cbuffer == 0 { + cbuffer = uint32(float64(ceil)/Hz() + float64(mtu)) + } + cbuffer = uint32(Xmittime(ceil, cbuffer)) + + return &HtbClass{ + ClassAttrs: attrs, + Rate: rate, + Ceil: ceil, + Buffer: buffer, + Cbuffer: cbuffer, + Quantum: 10, + Level: 0, + Prio: 0, + } +} + // ClassDel will delete a class from the system. // Equivalent to: `tc class del $class` func ClassDel(class Class) error { diff --git a/vendor/src/github.com/vishvananda/netlink/filter.go b/vendor/src/github.com/vishvananda/netlink/filter.go index 7e178ee00a..116aeba06e 100644 --- a/vendor/src/github.com/vishvananda/netlink/filter.go +++ b/vendor/src/github.com/vishvananda/netlink/filter.go @@ -1,11 +1,6 @@ package netlink -import ( - "errors" - "fmt" - - "github.com/vishvananda/netlink/nl" -) +import "fmt" type Filter interface { Attrs() *FilterAttrs @@ -217,74 +212,6 @@ type FilterFwAttrs struct { LinkLayer int } -// Fw filter filters on firewall marks -type Fw struct { - FilterAttrs - ClassId uint32 - // TODO remove nl type from interface - Police nl.TcPolice - InDev string - // TODO Action - Mask uint32 - AvRate uint32 - Rtab [256]uint32 - Ptab [256]uint32 -} - -func NewFw(attrs FilterAttrs, fattrs FilterFwAttrs) (*Fw, error) { - var rtab [256]uint32 - var ptab [256]uint32 - rcellLog := -1 - pcellLog := -1 - avrate := fattrs.AvRate / 8 - police := nl.TcPolice{} - police.Rate.Rate = fattrs.Rate / 8 - police.PeakRate.Rate = fattrs.PeakRate / 8 - buffer := fattrs.Buffer - linklayer := nl.LINKLAYER_ETHERNET - - if fattrs.LinkLayer != nl.LINKLAYER_UNSPEC { - linklayer = fattrs.LinkLayer - } - - police.Action = int32(fattrs.Action) - if police.Rate.Rate != 0 { - police.Rate.Mpu = fattrs.Mpu - police.Rate.Overhead = fattrs.Overhead - if CalcRtable(&police.Rate, rtab, rcellLog, fattrs.Mtu, linklayer) < 0 { - return nil, errors.New("TBF: failed to calculate rate table") - } - police.Burst = uint32(Xmittime(uint64(police.Rate.Rate), uint32(buffer))) - } - police.Mtu = fattrs.Mtu - if police.PeakRate.Rate != 0 { - police.PeakRate.Mpu = fattrs.Mpu - police.PeakRate.Overhead = fattrs.Overhead - if CalcRtable(&police.PeakRate, ptab, pcellLog, fattrs.Mtu, linklayer) < 0 { - return nil, errors.New("POLICE: failed to calculate peak rate table") - } - } - - return &Fw{ - FilterAttrs: attrs, - ClassId: fattrs.ClassId, - InDev: fattrs.InDev, - Mask: fattrs.Mask, - Police: police, - AvRate: avrate, - Rtab: rtab, - Ptab: ptab, - }, nil -} - -func (filter *Fw) Attrs() *FilterAttrs { - return &filter.FilterAttrs -} - -func (filter *Fw) Type() string { - return "fw" -} - type BpfFilter struct { FilterAttrs ClassId uint32 diff --git a/vendor/src/github.com/vishvananda/netlink/filter_linux.go b/vendor/src/github.com/vishvananda/netlink/filter_linux.go index 2a8cf89022..b403dad2f8 100644 --- a/vendor/src/github.com/vishvananda/netlink/filter_linux.go +++ b/vendor/src/github.com/vishvananda/netlink/filter_linux.go @@ -3,12 +3,83 @@ package netlink import ( "bytes" "encoding/binary" + "errors" "fmt" "syscall" "github.com/vishvananda/netlink/nl" ) +// Fw filter filters on firewall marks +// NOTE: this is in filter_linux because it refers to nl.TcPolice which +// is defined in nl/tc_linux.go +type Fw struct { + FilterAttrs + ClassId uint32 + // TODO remove nl type from interface + Police nl.TcPolice + InDev string + // TODO Action + Mask uint32 + AvRate uint32 + Rtab [256]uint32 + Ptab [256]uint32 +} + +func NewFw(attrs FilterAttrs, fattrs FilterFwAttrs) (*Fw, error) { + var rtab [256]uint32 + var ptab [256]uint32 + rcellLog := -1 + pcellLog := -1 + avrate := fattrs.AvRate / 8 + police := nl.TcPolice{} + police.Rate.Rate = fattrs.Rate / 8 + police.PeakRate.Rate = fattrs.PeakRate / 8 + buffer := fattrs.Buffer + linklayer := nl.LINKLAYER_ETHERNET + + if fattrs.LinkLayer != nl.LINKLAYER_UNSPEC { + linklayer = fattrs.LinkLayer + } + + police.Action = int32(fattrs.Action) + if police.Rate.Rate != 0 { + police.Rate.Mpu = fattrs.Mpu + police.Rate.Overhead = fattrs.Overhead + if CalcRtable(&police.Rate, rtab, rcellLog, fattrs.Mtu, linklayer) < 0 { + return nil, errors.New("TBF: failed to calculate rate table") + } + police.Burst = uint32(Xmittime(uint64(police.Rate.Rate), uint32(buffer))) + } + police.Mtu = fattrs.Mtu + if police.PeakRate.Rate != 0 { + police.PeakRate.Mpu = fattrs.Mpu + police.PeakRate.Overhead = fattrs.Overhead + if CalcRtable(&police.PeakRate, ptab, pcellLog, fattrs.Mtu, linklayer) < 0 { + return nil, errors.New("POLICE: failed to calculate peak rate table") + } + } + + return &Fw{ + FilterAttrs: attrs, + ClassId: fattrs.ClassId, + InDev: fattrs.InDev, + Mask: fattrs.Mask, + Police: police, + AvRate: avrate, + Rtab: rtab, + Ptab: ptab, + }, nil +} + +func (filter *Fw) Attrs() *FilterAttrs { + return &filter.FilterAttrs +} + +func (filter *Fw) Type() string { + return "fw" +} + // FilterDel will delete a filter from the system. // Equivalent to: `tc filter del $filter` func FilterDel(filter Filter) error { @@ -126,14 +197,14 @@ func (h *Handle) FilterAdd(filter Filter) error { // FilterList gets a list of filters in the system. // Equivalent to: `tc filter show`. -// Generally retunrs nothing if link and parent are not specified. +// Generally returns nothing if link and parent are not specified. func FilterList(link Link, parent uint32) ([]Filter, error) { return pkgHandle.FilterList(link, parent) } // FilterList gets a list of filters in the system. // Equivalent to: `tc filter show`. -// Generally retunrs nothing if link and parent are not specified. +// Generally returns nothing if link and parent are not specified. func (h *Handle) FilterList(link Link, parent uint32) ([]Filter, error) { req := h.newNetlinkRequest(syscall.RTM_GETTFILTER, syscall.NLM_F_DUMP) msg := &nl.TcMsg{ diff --git a/vendor/src/github.com/vishvananda/netlink/handle.go b/vendor/src/github.com/vishvananda/netlink/handle.go deleted file mode 100644 index a96d2397f4..0000000000 --- a/vendor/src/github.com/vishvananda/netlink/handle.go +++ /dev/null @@ -1,86 +0,0 @@ -package netlink - -import ( - "sync/atomic" - "syscall" - - "github.com/vishvananda/netlink/nl" - "github.com/vishvananda/netns" -) - -// Empty handle used by the netlink package methods -var pkgHandle = &Handle{} - -// Handle is an handle for the netlink requests -// on a specific network namespace. All the requests -// share the same netlink socket, which gets released -// when the handle is deleted. -type Handle struct { - seq uint32 - routeSocket *nl.NetlinkSocket - xfrmSocket *nl.NetlinkSocket - lookupByDump bool -} - -// NewHandle returns a netlink handle on the current network namespace. -func NewHandle() (*Handle, error) { - return newHandle(netns.None(), netns.None()) -} - -// NewHandle returns a netlink handle on the network namespace -// specified by ns. If ns=netns.None(), current network namespace -// will be assumed -func NewHandleAt(ns netns.NsHandle) (*Handle, error) { - return newHandle(ns, netns.None()) -} - -// NewHandleAtFrom works as NewHandle but allows client to specify the -// new and the origin netns Handle. -func NewHandleAtFrom(newNs, curNs netns.NsHandle) (*Handle, error) { - return newHandle(newNs, curNs) -} - -func newHandle(newNs, curNs netns.NsHandle) (*Handle, error) { - var ( - err error - rSocket *nl.NetlinkSocket - xSocket *nl.NetlinkSocket - ) - rSocket, err = nl.GetNetlinkSocketAt(newNs, curNs, syscall.NETLINK_ROUTE) - if err != nil { - return nil, err - } - xSocket, err = nl.GetNetlinkSocketAt(newNs, curNs, syscall.NETLINK_XFRM) - if err != nil { - return nil, err - } - return &Handle{routeSocket: rSocket, xfrmSocket: xSocket}, nil -} - -// Delete releases the resources allocated to this handle -func (h *Handle) Delete() { - if h.routeSocket != nil { - h.routeSocket.Close() - } - if h.xfrmSocket != nil { - h.xfrmSocket.Close() - } - h.routeSocket, h.xfrmSocket = nil, nil -} - -func (h *Handle) newNetlinkRequest(proto, flags int) *nl.NetlinkRequest { - // Do this so that package API still use nl package variable nextSeqNr - if h.routeSocket == nil { - return nl.NewNetlinkRequest(proto, flags) - } - return &nl.NetlinkRequest{ - NlMsghdr: syscall.NlMsghdr{ - Len: uint32(syscall.SizeofNlMsghdr), - Type: uint16(proto), - Flags: syscall.NLM_F_REQUEST | uint16(flags), - Seq: atomic.AddUint32(&h.seq, 1), - }, - RouteSocket: h.routeSocket, - XfmrSocket: h.xfrmSocket, - } -} diff --git a/vendor/src/github.com/vishvananda/netlink/handle_linux.go b/vendor/src/github.com/vishvananda/netlink/handle_linux.go new file mode 100644 index 0000000000..5377988752 --- /dev/null +++ b/vendor/src/github.com/vishvananda/netlink/handle_linux.go @@ -0,0 +1,86 @@ +package netlink + +import ( + "syscall" + + "github.com/vishvananda/netlink/nl" + "github.com/vishvananda/netns" +) + +// Empty handle used by the netlink package methods +var pkgHandle = &Handle{} + +// Handle is an handle for the netlink requests on a +// specific network namespace. All the requests on the +// same netlink family share the same netlink socket, +// which gets released when the handle is deleted. +type Handle struct { + sockets map[int]*nl.SocketHandle + lookupByDump bool +} + +// SupportsNetlinkFamily reports whether the passed netlink family is supported by this Handle +func (h *Handle) SupportsNetlinkFamily(nlFamily int) bool { + _, ok := h.sockets[nlFamily] + return ok +} + +// NewHandle returns a netlink handle on the current network namespace. +// Caller may specify the netlink families the handle should support. +// If no families are specified, all the families the netlink package +// supports will be automatically added. +func NewHandle(nlFamilies ...int) (*Handle, error) { + return newHandle(netns.None(), netns.None(), nlFamilies...) +} + +// NewHandle returns a netlink handle on the network namespace +// specified by ns. If ns=netns.None(), current network namespace +// will be assumed +func NewHandleAt(ns netns.NsHandle, nlFamilies ...int) (*Handle, error) { + return newHandle(ns, netns.None(), nlFamilies...) +} + +// NewHandleAtFrom works as NewHandle but allows client to specify the +// new and the origin netns Handle. +func NewHandleAtFrom(newNs, curNs netns.NsHandle) (*Handle, error) { + return newHandle(newNs, curNs) +} + +func newHandle(newNs, curNs netns.NsHandle, nlFamilies ...int) (*Handle, error) { + h := &Handle{sockets: map[int]*nl.SocketHandle{}} + fams := nl.SupportedNlFamilies + if len(nlFamilies) != 0 { + fams = nlFamilies + } + for _, f := range fams { + s, err := nl.GetNetlinkSocketAt(newNs, curNs, f) + if err != nil { + return nil, err + } + h.sockets[f] = &nl.SocketHandle{Socket: s} + } + return h, nil +} + +// Delete releases the resources allocated to this handle +func (h *Handle) Delete() { + for _, sh := range h.sockets { + sh.Close() + } + h.sockets = nil +} + +func (h *Handle) newNetlinkRequest(proto, flags int) *nl.NetlinkRequest { + // Do this so that package API still use nl package variable nextSeqNr + if h.sockets == nil { + return nl.NewNetlinkRequest(proto, flags) + } + return &nl.NetlinkRequest{ + NlMsghdr: syscall.NlMsghdr{ + Len: uint32(syscall.SizeofNlMsghdr), + Type: uint16(proto), + Flags: syscall.NLM_F_REQUEST | uint16(flags), + }, + Sockets: h.sockets, + } +} diff --git a/vendor/src/github.com/vishvananda/netlink/link.go b/vendor/src/github.com/vishvananda/netlink/link.go index 4efd32cbf2..9dbc221506 100644 --- a/vendor/src/github.com/vishvananda/netlink/link.go +++ b/vendor/src/github.com/vishvananda/netlink/link.go @@ -3,7 +3,6 @@ package netlink import ( "fmt" "net" - "syscall" ) // Link represents a link device from netlink. Shared link attributes @@ -173,11 +172,6 @@ func (macvtap Macvtap) Type() string { type TuntapMode uint16 -const ( - TUNTAP_MODE_TUN TuntapMode = syscall.IFF_TUN - TUNTAP_MODE_TAP TuntapMode = syscall.IFF_TAP -) - // Tuntap links created via /dev/tun/tap, but can be destroyed via netlink type Tuntap struct { LinkAttrs diff --git a/vendor/src/github.com/vishvananda/netlink/link_linux.go b/vendor/src/github.com/vishvananda/netlink/link_linux.go index 0ed307dd25..08a93843d6 100644 --- a/vendor/src/github.com/vishvananda/netlink/link_linux.go +++ b/vendor/src/github.com/vishvananda/netlink/link_linux.go @@ -14,6 +14,11 @@ import ( const SizeofLinkStats = 0x5c +const ( + TUNTAP_MODE_TUN TuntapMode = syscall.IFF_TUN + TUNTAP_MODE_TAP TuntapMode = syscall.IFF_TAP +) + var native = nl.NativeEndian() var lookupByDump = false @@ -675,6 +680,11 @@ func (h *Handle) LinkAdd(link Link) error { data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil) nl.NewRtAttrChild(data, nl.IFLA_MACVLAN_MODE, nl.Uint32Attr(macvlanModes[macv.Mode])) } + } else if macv, ok := link.(*Macvtap); ok { + if macv.Mode != MACVLAN_MODE_DEFAULT { + data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil) + nl.NewRtAttrChild(data, nl.IFLA_MACVLAN_MODE, nl.Uint32Attr(macvlanModes[macv.Mode])) + } } else if gretap, ok := link.(*Gretap); ok { addGretapAttrs(gretap, linkInfo) } diff --git a/vendor/src/github.com/vishvananda/netlink/netlink.go b/vendor/src/github.com/vishvananda/netlink/netlink.go index deafb6cfa7..d8e02f479f 100644 --- a/vendor/src/github.com/vishvananda/netlink/netlink.go +++ b/vendor/src/github.com/vishvananda/netlink/netlink.go @@ -8,18 +8,7 @@ // interface that is loosly modeled on the iproute2 cli. package netlink -import ( - "net" - - "github.com/vishvananda/netlink/nl" -) - -// Family type definitions -const ( - FAMILY_ALL = nl.FAMILY_ALL - FAMILY_V4 = nl.FAMILY_V4 - FAMILY_V6 = nl.FAMILY_V6 -) +import "net" // ParseIPNet parses a string in ip/net format and returns a net.IPNet. // This is valuable because addresses in netlink are often IPNets and diff --git a/vendor/src/github.com/vishvananda/netlink/netlink_linux.go b/vendor/src/github.com/vishvananda/netlink/netlink_linux.go new file mode 100644 index 0000000000..32d8537ef4 --- /dev/null +++ b/vendor/src/github.com/vishvananda/netlink/netlink_linux.go @@ -0,0 +1,10 @@ +package netlink + +import "github.com/vishvananda/netlink/nl" + +// Family type definitions +const ( + FAMILY_ALL = nl.FAMILY_ALL + FAMILY_V4 = nl.FAMILY_V4 + FAMILY_V6 = nl.FAMILY_V6 +) diff --git a/vendor/src/github.com/vishvananda/netlink/netlink_unspecified.go b/vendor/src/github.com/vishvananda/netlink/netlink_unspecified.go index 10c49c1bfc..9ad7a62875 100644 --- a/vendor/src/github.com/vishvananda/netlink/netlink_unspecified.go +++ b/vendor/src/github.com/vishvananda/netlink/netlink_unspecified.go @@ -138,6 +138,6 @@ func NeighList(linkIndex, family int) ([]Neigh, error) { return nil, ErrNotImplemented } -func NeighDeserialize(m []byte) (*Ndmsg, *Neigh, error) { - return nil, nil, ErrNotImplemented +func NeighDeserialize(m []byte) (*Neigh, error) { + return nil, ErrNotImplemented } diff --git a/vendor/src/github.com/vishvananda/netlink/nl/nl_linux.go b/vendor/src/github.com/vishvananda/netlink/nl/nl_linux.go index f41821dd72..fd5550a306 100644 --- a/vendor/src/github.com/vishvananda/netlink/nl/nl_linux.go +++ b/vendor/src/github.com/vishvananda/netlink/nl/nl_linux.go @@ -22,6 +22,9 @@ const ( FAMILY_V6 = syscall.AF_INET6 ) +// SupportedNlFamilies contains the list of netlink families this netlink package supports +var SupportedNlFamilies = []int{syscall.NETLINK_ROUTE, syscall.NETLINK_XFRM} + var nextSeqNr uint32 // GetIPFamily returns the family type of a net.IP. @@ -175,9 +178,8 @@ func (a *RtAttr) Serialize() []byte { type NetlinkRequest struct { syscall.NlMsghdr - Data []NetlinkRequestData - RouteSocket *NetlinkSocket - XfmrSocket *NetlinkSocket + Data []NetlinkRequestData + Sockets map[int]*SocketHandle } // Serialize the Netlink Request into a byte array @@ -209,7 +211,7 @@ func (req *NetlinkRequest) AddData(data NetlinkRequestData) { } // Execute the request against a the given sockType. -// Returns a list of netlink messages in seriaized format, optionally filtered +// Returns a list of netlink messages in serialized format, optionally filtered // by resType. func (req *NetlinkRequest) Execute(sockType int, resType uint16) ([][]byte, error) { var ( @@ -217,15 +219,12 @@ func (req *NetlinkRequest) Execute(sockType int, resType uint16) ([][]byte, erro err error ) - switch sockType { - case syscall.NETLINK_XFRM: - s = req.XfmrSocket - case syscall.NETLINK_ROUTE: - s = req.RouteSocket - default: - return nil, fmt.Errorf("Socket type %d is not handled", sockType) + if req.Sockets != nil { + if sh, ok := req.Sockets[sockType]; ok { + s = sh.Socket + req.Seq = atomic.AddUint32(&sh.Seq, 1) + } } - sharedSocket := s != nil if s == nil { @@ -486,3 +485,17 @@ func netlinkRouteAttrAndValue(b []byte) (*syscall.RtAttr, []byte, int, error) { } return a, b[syscall.SizeofRtAttr:], rtaAlignOf(int(a.Len)), nil } + +// SocketHandle contains the netlink socket and the associated +// sequence counter for a specific netlink family +type SocketHandle struct { + Seq uint32 + Socket *NetlinkSocket +} + +// Close closes the netlink socket +func (sh *SocketHandle) Close() { + if sh.Socket != nil { + sh.Socket.Close() + } +} diff --git a/vendor/src/github.com/vishvananda/netlink/nl/route_linux.go b/vendor/src/github.com/vishvananda/netlink/nl/route_linux.go index 447e83e5ae..f7db88dfee 100644 --- a/vendor/src/github.com/vishvananda/netlink/nl/route_linux.go +++ b/vendor/src/github.com/vishvananda/netlink/nl/route_linux.go @@ -40,3 +40,15 @@ func DeserializeRtMsg(b []byte) *RtMsg { func (msg *RtMsg) Serialize() []byte { return (*(*[syscall.SizeofRtMsg]byte)(unsafe.Pointer(msg)))[:] } + +type RtNexthop struct { + syscall.RtNexthop +} + +func DeserializeRtNexthop(b []byte) *RtNexthop { + return (*RtNexthop)(unsafe.Pointer(&b[0:syscall.SizeofRtNexthop][0])) +} + +func (msg *RtNexthop) Serialize() []byte { + return (*(*[syscall.SizeofRtNexthop]byte)(unsafe.Pointer(msg)))[:] +} diff --git a/vendor/src/github.com/vishvananda/netlink/qdisc.go b/vendor/src/github.com/vishvananda/netlink/qdisc.go index 3fb2bbae24..28f65f3894 100644 --- a/vendor/src/github.com/vishvananda/netlink/qdisc.go +++ b/vendor/src/github.com/vishvananda/netlink/qdisc.go @@ -176,70 +176,6 @@ type Netem struct { CorruptCorr uint32 } -func NewNetem(attrs QdiscAttrs, nattrs NetemQdiscAttrs) *Netem { - var limit uint32 = 1000 - var lossCorr, delayCorr, duplicateCorr uint32 - var reorderProb, reorderCorr uint32 - var corruptProb, corruptCorr uint32 - - latency := nattrs.Latency - loss := Percentage2u32(nattrs.Loss) - gap := nattrs.Gap - duplicate := Percentage2u32(nattrs.Duplicate) - jitter := nattrs.Jitter - - // Correlation - if latency > 0 && jitter > 0 { - delayCorr = Percentage2u32(nattrs.DelayCorr) - } - if loss > 0 { - lossCorr = Percentage2u32(nattrs.LossCorr) - } - if duplicate > 0 { - duplicateCorr = Percentage2u32(nattrs.DuplicateCorr) - } - // FIXME should validate values(like loss/duplicate are percentages...) - latency = time2Tick(latency) - - if nattrs.Limit != 0 { - limit = nattrs.Limit - } - // Jitter is only value if latency is > 0 - if latency > 0 { - jitter = time2Tick(jitter) - } - - reorderProb = Percentage2u32(nattrs.ReorderProb) - reorderCorr = Percentage2u32(nattrs.ReorderCorr) - - if reorderProb > 0 { - // ERROR if lantency == 0 - if gap == 0 { - gap = 1 - } - } - - corruptProb = Percentage2u32(nattrs.CorruptProb) - corruptCorr = Percentage2u32(nattrs.CorruptCorr) - - return &Netem{ - QdiscAttrs: attrs, - Latency: latency, - DelayCorr: delayCorr, - Limit: limit, - Loss: loss, - LossCorr: lossCorr, - Gap: gap, - Duplicate: duplicate, - DuplicateCorr: duplicateCorr, - Jitter: jitter, - ReorderProb: reorderProb, - ReorderCorr: reorderCorr, - CorruptProb: corruptProb, - CorruptCorr: corruptCorr, - } -} - func (qdisc *Netem) Attrs() *QdiscAttrs { return &qdisc.QdiscAttrs } diff --git a/vendor/src/github.com/vishvananda/netlink/qdisc_linux.go b/vendor/src/github.com/vishvananda/netlink/qdisc_linux.go index 62ac9d3dd8..1bb485646b 100644 --- a/vendor/src/github.com/vishvananda/netlink/qdisc_linux.go +++ b/vendor/src/github.com/vishvananda/netlink/qdisc_linux.go @@ -10,6 +10,71 @@ import ( "github.com/vishvananda/netlink/nl" ) +// NOTE function is here because it uses other linux functions +func NewNetem(attrs QdiscAttrs, nattrs NetemQdiscAttrs) *Netem { + var limit uint32 = 1000 + var lossCorr, delayCorr, duplicateCorr uint32 + var reorderProb, reorderCorr uint32 + var corruptProb, corruptCorr uint32 + + latency := nattrs.Latency + loss := Percentage2u32(nattrs.Loss) + gap := nattrs.Gap + duplicate := Percentage2u32(nattrs.Duplicate) + jitter := nattrs.Jitter + + // Correlation + if latency > 0 && jitter > 0 { + delayCorr = Percentage2u32(nattrs.DelayCorr) + } + if loss > 0 { + lossCorr = Percentage2u32(nattrs.LossCorr) + } + if duplicate > 0 { + duplicateCorr = Percentage2u32(nattrs.DuplicateCorr) + } + // FIXME should validate values(like loss/duplicate are percentages...) + latency = time2Tick(latency) + + if nattrs.Limit != 0 { + limit = nattrs.Limit + } + // Jitter is only value if latency is > 0 + if latency > 0 { + jitter = time2Tick(jitter) + } + + reorderProb = Percentage2u32(nattrs.ReorderProb) + reorderCorr = Percentage2u32(nattrs.ReorderCorr) + + if reorderProb > 0 { + // ERROR if lantency == 0 + if gap == 0 { + gap = 1 + } + } + + corruptProb = Percentage2u32(nattrs.CorruptProb) + corruptCorr = Percentage2u32(nattrs.CorruptCorr) + + return &Netem{ + QdiscAttrs: attrs, + Latency: latency, + DelayCorr: delayCorr, + Limit: limit, + Loss: loss, + LossCorr: lossCorr, + Gap: gap, + Duplicate: duplicate, + DuplicateCorr: duplicateCorr, + Jitter: jitter, + ReorderProb: reorderProb, + ReorderCorr: reorderCorr, + CorruptProb: corruptProb, + CorruptCorr: corruptCorr, + } +} + // QdiscDel will delete a qdisc from the system. // Equivalent to: `tc qdisc del $qdisc` func QdiscDel(qdisc Qdisc) error { diff --git a/vendor/src/github.com/vishvananda/netlink/route.go b/vendor/src/github.com/vishvananda/netlink/route.go index aa869ea93c..61cf5ec5e1 100644 --- a/vendor/src/github.com/vishvananda/netlink/route.go +++ b/vendor/src/github.com/vishvananda/netlink/route.go @@ -3,27 +3,13 @@ package netlink import ( "fmt" "net" - "syscall" ) // Scope is an enum representing a route scope. type Scope uint8 -const ( - SCOPE_UNIVERSE Scope = syscall.RT_SCOPE_UNIVERSE - SCOPE_SITE Scope = syscall.RT_SCOPE_SITE - SCOPE_LINK Scope = syscall.RT_SCOPE_LINK - SCOPE_HOST Scope = syscall.RT_SCOPE_HOST - SCOPE_NOWHERE Scope = syscall.RT_SCOPE_NOWHERE -) - type NextHopFlag int -const ( - FLAG_ONLINK NextHopFlag = syscall.RTNH_F_ONLINK - FLAG_PERVASIVE NextHopFlag = syscall.RTNH_F_PERVASIVE -) - // Route represents a netlink route. type Route struct { LinkIndex int @@ -32,6 +18,7 @@ type Route struct { Dst *net.IPNet Src net.IP Gw net.IP + MultiPath []*NexthopInfo Protocol int Priority int Table int @@ -41,6 +28,10 @@ type Route struct { } func (r Route) String() string { + if len(r.MultiPath) > 0 { + return fmt.Sprintf("{Dst: %s Src: %s Gw: %s Flags: %s Table: %d}", r.Dst, + r.Src, r.MultiPath, r.ListFlags(), r.Table) + } return fmt.Sprintf("{Ifindex: %d Dst: %s Src: %s Gw: %s Flags: %s Table: %d}", r.LinkIndex, r.Dst, r.Src, r.Gw, r.ListFlags(), r.Table) } @@ -58,23 +49,18 @@ type flagString struct { s string } -var testFlags = []flagString{ - {f: FLAG_ONLINK, s: "onlink"}, - {f: FLAG_PERVASIVE, s: "pervasive"}, -} - -func (r *Route) ListFlags() []string { - var flags []string - for _, tf := range testFlags { - if r.Flags&int(tf.f) != 0 { - flags = append(flags, tf.s) - } - } - return flags -} - // RouteUpdate is sent when a route changes - type is RTM_NEWROUTE or RTM_DELROUTE type RouteUpdate struct { Type uint16 Route } + +type NexthopInfo struct { + LinkIndex int + Hops int + Gw net.IP +} + +func (n *NexthopInfo) String() string { + return fmt.Sprintf("{Ifindex: %d Weight: %d, Gw: %s}", n.LinkIndex, n.Hops+1, n.Gw) +} diff --git a/vendor/src/github.com/vishvananda/netlink/route_linux.go b/vendor/src/github.com/vishvananda/netlink/route_linux.go index db952512e9..5d684ad795 100644 --- a/vendor/src/github.com/vishvananda/netlink/route_linux.go +++ b/vendor/src/github.com/vishvananda/netlink/route_linux.go @@ -10,6 +10,14 @@ import ( // RtAttr is shared so it is in netlink_linux.go +const ( + SCOPE_UNIVERSE Scope = syscall.RT_SCOPE_UNIVERSE + SCOPE_SITE Scope = syscall.RT_SCOPE_SITE + SCOPE_LINK Scope = syscall.RT_SCOPE_LINK + SCOPE_HOST Scope = syscall.RT_SCOPE_HOST + SCOPE_NOWHERE Scope = syscall.RT_SCOPE_NOWHERE +) + const ( RT_FILTER_PROTOCOL uint64 = 1 << (1 + iota) RT_FILTER_SCOPE @@ -23,6 +31,26 @@ const ( RT_FILTER_TABLE ) +const ( + FLAG_ONLINK NextHopFlag = syscall.RTNH_F_ONLINK + FLAG_PERVASIVE NextHopFlag = syscall.RTNH_F_PERVASIVE +) + +var testFlags = []flagString{ + {f: FLAG_ONLINK, s: "onlink"}, + {f: FLAG_PERVASIVE, s: "pervasive"}, +} + +func (r *Route) ListFlags() []string { + var flags []string + for _, tf := range testFlags { + if r.Flags&int(tf.f) != 0 { + flags = append(flags, tf.s) + } + } + return flags +} + // RouteAdd will add a route to the system. // Equivalent to: `ip route add $route` func RouteAdd(route *Route) error { @@ -102,6 +130,37 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_GATEWAY, gwData)) } + if len(route.MultiPath) > 0 { + buf := []byte{} + for _, nh := range route.MultiPath { + rtnh := &nl.RtNexthop{ + RtNexthop: syscall.RtNexthop{ + Hops: uint8(nh.Hops), + Ifindex: int32(nh.LinkIndex), + Len: uint16(syscall.SizeofRtNexthop), + }, + } + var gwData []byte + if nh.Gw != nil { + gwFamily := nl.GetIPFamily(nh.Gw) + if family != -1 && family != gwFamily { + return fmt.Errorf("gateway, source, and destination ip are not the same IP family") + } + var gw *nl.RtAttr + if gwFamily == FAMILY_V4 { + gw = nl.NewRtAttr(syscall.RTA_GATEWAY, []byte(nh.Gw.To4())) + } else { + gw = nl.NewRtAttr(syscall.RTA_GATEWAY, []byte(nh.Gw.To16())) + } + gwData := gw.Serialize() + rtnh.Len += uint16(len(gwData)) + } + buf = append(buf, rtnh.Serialize()...) + buf = append(buf, gwData...) + } + rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_MULTIPATH, buf)) + } + if route.Table > 0 { if route.Table >= 256 { msg.Table = syscall.RT_TABLE_UNSPEC @@ -275,6 +334,40 @@ func deserializeRoute(m []byte) (Route, error) { route.Priority = int(native.Uint32(attr.Value[0:4])) case syscall.RTA_TABLE: route.Table = int(native.Uint32(attr.Value[0:4])) + case syscall.RTA_MULTIPATH: + parseRtNexthop := func(value []byte) (*NexthopInfo, []byte, error) { + if len(value) < syscall.SizeofRtNexthop { + return nil, nil, fmt.Errorf("Lack of bytes") + } + nh := nl.DeserializeRtNexthop(value) + if len(value) < int(nh.RtNexthop.Len) { + return nil, nil, fmt.Errorf("Lack of bytes") + } + info := &NexthopInfo{ + LinkIndex: int(nh.RtNexthop.Ifindex), + Hops: int(nh.RtNexthop.Hops), + } + attrs, err := nl.ParseRouteAttr(value[syscall.SizeofRtNexthop:int(nh.RtNexthop.Len)]) + if err != nil { + return nil, nil, err + } + for _, attr := range attrs { + switch attr.Attr.Type { + case syscall.RTA_GATEWAY: + info.Gw = net.IP(attr.Value) + } + } + return info, value[int(nh.RtNexthop.Len):], nil + } + rest := attr.Value + for len(rest) > 0 { + info, buf, err := parseRtNexthop(rest) + if err != nil { + return route, err + } + route.MultiPath = append(route.MultiPath, info) + rest = buf + } } } return route, nil diff --git a/vendor/src/github.com/vishvananda/netlink/route_unspecified.go b/vendor/src/github.com/vishvananda/netlink/route_unspecified.go new file mode 100644 index 0000000000..1b20530646 --- /dev/null +++ b/vendor/src/github.com/vishvananda/netlink/route_unspecified.go @@ -0,0 +1,7 @@ +// +build !linux + +package netlink + +func (r *Route) ListFlags() []string { + return []string{} +} diff --git a/vendor/src/github.com/vishvananda/netlink/rule.go b/vendor/src/github.com/vishvananda/netlink/rule.go index bd699a7e12..f0243defd7 100644 --- a/vendor/src/github.com/vishvananda/netlink/rule.go +++ b/vendor/src/github.com/vishvananda/netlink/rule.go @@ -3,13 +3,10 @@ package netlink import ( "fmt" "net" - - "github.com/vishvananda/netlink/nl" ) // Rule represents a netlink rule. type Rule struct { - *nl.RtMsg Priority int Table int Mark int diff --git a/vendor/src/github.com/vishvananda/netlink/rule_linux.go b/vendor/src/github.com/vishvananda/netlink/rule_linux.go index 8bce6666c9..58fac557c0 100644 --- a/vendor/src/github.com/vishvananda/netlink/rule_linux.go +++ b/vendor/src/github.com/vishvananda/netlink/rule_linux.go @@ -165,7 +165,6 @@ func (h *Handle) RuleList(family int) ([]Rule, error) { } rule := NewRule() - rule.RtMsg = msg for j := range attrs { switch attrs[j].Attr.Type { diff --git a/vendor/src/github.com/vishvananda/netlink/xfrm.go b/vendor/src/github.com/vishvananda/netlink/xfrm.go index 6ec40acac9..9962dcf700 100644 --- a/vendor/src/github.com/vishvananda/netlink/xfrm.go +++ b/vendor/src/github.com/vishvananda/netlink/xfrm.go @@ -13,7 +13,7 @@ const ( XFRM_PROTO_ESP Proto = syscall.IPPROTO_ESP XFRM_PROTO_AH Proto = syscall.IPPROTO_AH XFRM_PROTO_HAO Proto = syscall.IPPROTO_DSTOPTS - XFRM_PROTO_COMP Proto = syscall.IPPROTO_COMP + XFRM_PROTO_COMP Proto = 0x6c // NOTE not defined on darwin XFRM_PROTO_IPSEC_ANY Proto = syscall.IPPROTO_RAW ) diff --git a/vendor/src/github.com/vishvananda/netlink/xfrm_state.go b/vendor/src/github.com/vishvananda/netlink/xfrm_state.go index 7f38bfa226..6ffbcdb476 100644 --- a/vendor/src/github.com/vishvananda/netlink/xfrm_state.go +++ b/vendor/src/github.com/vishvananda/netlink/xfrm_state.go @@ -3,8 +3,6 @@ package netlink import ( "fmt" "net" - - "github.com/vishvananda/netlink/nl" ) // XfrmStateAlgo represents the algorithm to use for the ipsec encryption. @@ -93,7 +91,7 @@ func (sa XfrmState) Print(stats bool) string { } func printLimit(lmt uint64) string { - if lmt == nl.XFRM_INF { + if lmt == ^uint64(0) { return "(INF)" } return fmt.Sprintf("%d", lmt) From e26c513fa818a57b4ea572121e153cf6f056e1ee Mon Sep 17 00:00:00 2001 From: Alessandro Boch Date: Wed, 22 Jun 2016 09:40:20 -0700 Subject: [PATCH 2/3] Vendoring libnetwork ed311d0 Signed-off-by: Alessandro Boch --- hack/vendor.sh | 2 +- .../src/github.com/docker/libnetwork/agent.go | 171 ++++++++++++++---- .../docker/libnetwork/controller.go | 3 + .../libnetwork/discoverapi/discoverapi.go | 16 +- .../libnetwork/drivers/overlay/encryption.go | 25 +-- .../libnetwork/drivers/overlay/joinleave.go | 9 +- .../libnetwork/drivers/overlay/ov_network.go | 2 +- .../libnetwork/drivers/overlay/ov_utils.go | 3 +- .../libnetwork/drivers/overlay/overlay.go | 30 +-- .../docker/libnetwork/networkdb/cluster.go | 7 + .../docker/libnetwork/ns/init_linux.go | 24 ++- .../docker/libnetwork/osl/interface_linux.go | 8 +- .../docker/libnetwork/osl/namespace_linux.go | 6 +- .../github.com/docker/libnetwork/resolver.go | 98 +++++++++- 14 files changed, 312 insertions(+), 92 deletions(-) diff --git a/hack/vendor.sh b/hack/vendor.sh index 1f16ff58a1..4a68b5799b 100755 --- a/hack/vendor.sh +++ b/hack/vendor.sh @@ -65,7 +65,7 @@ clone git github.com/RackSec/srslog 259aed10dfa74ea2961eddd1d9847619f6e98837 clone git github.com/imdario/mergo 0.2.1 #get libnetwork packages -clone git github.com/docker/libnetwork ab62dd6bf06bf0637d66d529931b69a5544468cb +clone git github.com/docker/libnetwork ed311d050fda7821f2e7c53a7e08a0205923aef5 clone git github.com/docker/go-events 39718a26497694185f8fb58a7d6f31947f3dc42d clone git github.com/armon/go-radix e39d623f12e8e41c7b5529e9a9dd67a1e2261f80 clone git github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec diff --git a/vendor/src/github.com/docker/libnetwork/agent.go b/vendor/src/github.com/docker/libnetwork/agent.go index 6215459d8d..eaab2893c0 100644 --- a/vendor/src/github.com/docker/libnetwork/agent.go +++ b/vendor/src/github.com/docker/libnetwork/agent.go @@ -3,12 +3,10 @@ package libnetwork //go:generate protoc -I.:Godeps/_workspace/src/github.com/gogo/protobuf --gogo_out=import_path=github.com/docker/libnetwork,Mgogoproto/gogo.proto=github.com/gogo/protobuf/gogoproto:. agent.proto import ( - "encoding/hex" "fmt" "net" "os" "sort" - "strconv" "github.com/Sirupsen/logrus" "github.com/docker/go-events" @@ -20,6 +18,12 @@ import ( "github.com/gogo/protobuf/proto" ) +const ( + subsysGossip = "networking:gossip" + subsysIPSec = "networking:ipsec" + keyringSize = 3 +) + // ByTime implements sort.Interface for []*types.EncryptionKey based on // the LamportTime field. type ByTime []*types.EncryptionKey @@ -80,6 +84,82 @@ func resolveAddr(addrOrInterface string) (string, error) { func (c *controller) handleKeyChange(keys []*types.EncryptionKey) error { drvEnc := discoverapi.DriverEncryptionUpdate{} + a := c.agent + // Find the deleted key. If the deleted key was the primary key, + // a new primary key should be set before removing if from keyring. + deleted := []byte{} + j := len(c.keys) + for i := 0; i < j; { + same := false + for _, key := range keys { + if same = key.LamportTime == c.keys[i].LamportTime; same { + break + } + } + if !same { + cKey := c.keys[i] + if cKey.Subsystem == subsysGossip { + deleted = cKey.Key + } + + if cKey.Subsystem == subsysGossip /* subsysIPSec */ { + drvEnc.Prune = cKey.Key + drvEnc.PruneTag = cKey.LamportTime + } + c.keys[i], c.keys[j-1] = c.keys[j-1], c.keys[i] + c.keys[j-1] = nil + j-- + } + i++ + } + c.keys = c.keys[:j] + + // Find the new key and add it to the key ring + for _, key := range keys { + same := false + for _, cKey := range c.keys { + if same = cKey.LamportTime == key.LamportTime; same { + break + } + } + if !same { + c.keys = append(c.keys, key) + if key.Subsystem == subsysGossip { + a.networkDB.SetKey(key.Key) + } + + if key.Subsystem == subsysGossip /*subsysIPSec*/ { + drvEnc.Key = key.Key + drvEnc.Tag = key.LamportTime + } + } + } + + key, tag := c.getPrimaryKeyTag(subsysGossip) + a.networkDB.SetPrimaryKey(key) + + //key, tag = c.getPrimaryKeyTag(subsysIPSec) + drvEnc.Primary = key + drvEnc.PrimaryTag = tag + + if len(deleted) > 0 { + a.networkDB.RemoveKey(deleted) + } + + c.drvRegistry.WalkDrivers(func(name string, driver driverapi.Driver, capability driverapi.Capability) bool { + err := driver.DiscoverNew(discoverapi.EncryptionKeysUpdate, drvEnc) + if err != nil { + logrus.Warnf("Failed to update datapath keys in driver %s: %v", name, err) + } + return false + }) + + return nil +} + +func (c *controller) handleKeyChangeV1(keys []*types.EncryptionKey) error { + drvEnc := discoverapi.DriverEncryptionUpdate{} + // Find the new key and add it to the key ring a := c.agent for _, key := range keys { @@ -91,12 +171,12 @@ func (c *controller) handleKeyChange(keys []*types.EncryptionKey) error { } if !same { c.keys = append(c.keys, key) - if key.Subsystem == "networking:gossip" { + if key.Subsystem == subsysGossip { a.networkDB.SetKey(key.Key) } - if key.Subsystem == "networking:gossip" /*"networking:ipsec"*/ { - drvEnc.Key = hex.EncodeToString(key.Key) - drvEnc.Tag = strconv.FormatUint(key.LamportTime, 10) + if key.Subsystem == subsysGossip /*subsysIPSec*/ { + drvEnc.Key = key.Key + drvEnc.Tag = key.LamportTime } break } @@ -112,12 +192,12 @@ func (c *controller) handleKeyChange(keys []*types.EncryptionKey) error { } } if !same { - if cKey.Subsystem == "networking:gossip" { + if cKey.Subsystem == subsysGossip { deleted = cKey.Key } - if cKey.Subsystem == "networking:gossip" /*"networking:ipsec"*/ { - drvEnc.Prune = hex.EncodeToString(cKey.Key) - drvEnc.PruneTag = strconv.FormatUint(cKey.LamportTime, 10) + if cKey.Subsystem == subsysGossip /*subsysIPSec*/ { + drvEnc.Prune = cKey.Key + drvEnc.PruneTag = cKey.LamportTime } c.keys = append(c.keys[:i], c.keys[i+1:]...) break @@ -126,15 +206,15 @@ func (c *controller) handleKeyChange(keys []*types.EncryptionKey) error { sort.Sort(ByTime(c.keys)) for _, key := range c.keys { - if key.Subsystem == "networking:gossip" { + if key.Subsystem == subsysGossip { a.networkDB.SetPrimaryKey(key.Key) break } } for _, key := range c.keys { - if key.Subsystem == "networking:gossip" /*"networking:ipsec"*/ { - drvEnc.Primary = hex.EncodeToString(key.Key) - drvEnc.PrimaryTag = strconv.FormatUint(key.LamportTime, 10) + if key.Subsystem == subsysGossip /*subsysIPSec*/ { + drvEnc.Primary = key.Key + drvEnc.PrimaryTag = key.LamportTime break } } @@ -197,6 +277,41 @@ func (c *controller) agentSetup() error { return nil } +// For a given subsystem getKeys sorts the keys by lamport time and returns +// slice of keys and lamport time which can used as a unique tag for the keys +func (c *controller) getKeys(subsys string) ([][]byte, []uint64) { + sort.Sort(ByTime(c.keys)) + + keys := [][]byte{} + tags := []uint64{} + for _, key := range c.keys { + if key.Subsystem == subsys { + keys = append(keys, key.Key) + tags = append(tags, key.LamportTime) + } + } + + if len(keys) < keyringSize { + return keys, tags + } + keys[0], keys[1] = keys[1], keys[0] + tags[0], tags[1] = tags[1], tags[0] + return keys, tags +} + +// getPrimaryKeyTag returns the primary key for a given subsytem from the +// list of sorted key and the associated tag +func (c *controller) getPrimaryKeyTag(subsys string) ([]byte, uint64) { + sort.Sort(ByTime(c.keys)) + keys := []*types.EncryptionKey{} + for _, key := range c.keys { + if key.Subsystem == subsys { + keys = append(keys, key) + } + } + return keys[1].Key, keys[1].LamportTime +} + func (c *controller) agentInit(bindAddrOrInterface string) error { if !c.isAgent() { return nil @@ -204,19 +319,9 @@ func (c *controller) agentInit(bindAddrOrInterface string) error { drvEnc := discoverapi.DriverEncryptionConfig{} - // sort the keys by lamport time - sort.Sort(ByTime(c.keys)) - - gossipkey := [][]byte{} - for _, key := range c.keys { - if key.Subsystem == "networking:gossip" { - gossipkey = append(gossipkey, key.Key) - } - if key.Subsystem == "networking:gossip" /*"networking:ipsec"*/ { - drvEnc.Keys = append(drvEnc.Keys, hex.EncodeToString(key.Key)) - drvEnc.Tags = append(drvEnc.Tags, strconv.FormatUint(key.LamportTime, 10)) - } - } + keys, tags := c.getKeys(subsysGossip) // getKeys(subsysIPSec) + drvEnc.Keys = keys + drvEnc.Tags = tags bindAddr, err := resolveAddr(bindAddrOrInterface) if err != nil { @@ -227,7 +332,7 @@ func (c *controller) agentInit(bindAddrOrInterface string) error { nDB, err := networkdb.New(&networkdb.Config{ BindAddr: bindAddr, NodeName: hostname, - Keys: gossipkey, + Keys: keys, }) if err != nil { @@ -275,12 +380,10 @@ func (c *controller) agentDriverNotify(d driverapi.Driver) { }) drvEnc := discoverapi.DriverEncryptionConfig{} - for _, key := range c.keys { - if key.Subsystem == "networking:gossip" /*"networking:ipsec"*/ { - drvEnc.Keys = append(drvEnc.Keys, hex.EncodeToString(key.Key)) - drvEnc.Tags = append(drvEnc.Tags, strconv.FormatUint(key.LamportTime, 10)) - } - } + keys, tags := c.getKeys(subsysGossip) // getKeys(subsysIPSec) + drvEnc.Keys = keys + drvEnc.Tags = tags + c.drvRegistry.WalkDrivers(func(name string, driver driverapi.Driver, capability driverapi.Capability) bool { err := driver.DiscoverNew(discoverapi.EncryptionKeysConfig, drvEnc) if err != nil { diff --git a/vendor/src/github.com/docker/libnetwork/controller.go b/vendor/src/github.com/docker/libnetwork/controller.go index 1646568f27..80ccf6e6e2 100644 --- a/vendor/src/github.com/docker/libnetwork/controller.go +++ b/vendor/src/github.com/docker/libnetwork/controller.go @@ -264,6 +264,9 @@ func (c *controller) SetKeys(keys []*types.EncryptionKey) error { c.Unlock() return nil } + if len(keys) < keyringSize { + return c.handleKeyChangeV1(keys) + } return c.handleKeyChange(keys) } diff --git a/vendor/src/github.com/docker/libnetwork/discoverapi/discoverapi.go b/vendor/src/github.com/docker/libnetwork/discoverapi/discoverapi.go index 080424a182..bee7ad1837 100644 --- a/vendor/src/github.com/docker/libnetwork/discoverapi/discoverapi.go +++ b/vendor/src/github.com/docker/libnetwork/discoverapi/discoverapi.go @@ -42,18 +42,18 @@ type DatastoreConfigData struct { // Key in first position is the primary key, the one to be used in tx. // Original key and tag types are []byte and uint64 type DriverEncryptionConfig struct { - Keys []string - Tags []string + Keys [][]byte + Tags []uint64 } // DriverEncryptionUpdate carries an update to the encryption key(s) as: // a new key and/or set a primary key and/or a removal of an existing key. // Original key and tag types are []byte and uint64 type DriverEncryptionUpdate struct { - Key string - Tag string - Primary string - PrimaryTag string - Prune string - PruneTag string + Key []byte + Tag uint64 + Primary []byte + PrimaryTag uint64 + Prune []byte + PruneTag uint64 } diff --git a/vendor/src/github.com/docker/libnetwork/drivers/overlay/encryption.go b/vendor/src/github.com/docker/libnetwork/drivers/overlay/encryption.go index f27f86004d..36d2a2f2b7 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/overlay/encryption.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/overlay/encryption.go @@ -33,7 +33,10 @@ type key struct { } func (k *key) String() string { - return fmt.Sprintf("(key: %s, tag: 0x%x)", hex.EncodeToString(k.value)[0:5], k.tag) + if k != nil { + return fmt.Sprintf("(key: %s, tag: 0x%x)", hex.EncodeToString(k.value)[0:5], k.tag) + } + return "" } type spi struct { @@ -557,23 +560,3 @@ func updateNodeKey(lIP, rIP net.IP, idxs []*spi, curKeys []*key, newIdx, priIdx, return spis } - -func parseEncryptionKey(value, tag string) (*key, error) { - var ( - k *key - err error - ) - if value == "" { - return nil, nil - } - k = &key{} - if k.value, err = hex.DecodeString(value); err != nil { - return nil, types.BadRequestErrorf("failed to decode key (%s): %v", value, err) - } - t, err := strconv.ParseUint(tag, 10, 64) - if err != nil { - return nil, types.BadRequestErrorf("failed to decode tag (%s): %v", tag, err) - } - k.tag = uint32(t) - return k, nil -} diff --git a/vendor/src/github.com/docker/libnetwork/drivers/overlay/joinleave.go b/vendor/src/github.com/docker/libnetwork/drivers/overlay/joinleave.go index 8cdf3194de..1f21ee9b0d 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/overlay/joinleave.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/overlay/joinleave.go @@ -3,6 +3,7 @@ package overlay import ( "fmt" "net" + "syscall" log "github.com/Sirupsen/logrus" "github.com/docker/libnetwork/driverapi" @@ -31,6 +32,12 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, return fmt.Errorf("cannot join secure network: encryption keys not present") } + nlh := ns.NlHandle() + + if n.secure && !nlh.SupportsNetlinkFamily(syscall.NETLINK_XFRM) { + return fmt.Errorf("cannot join secure network: required modules to install IPSEC rules are missing on host") + } + s := n.getSubnetforIP(ep.addr) if s == nil { return fmt.Errorf("could not find subnet for endpoint %s", eid) @@ -65,8 +72,6 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, return fmt.Errorf("failed to update overlay endpoint %s to local data store: %v", ep.id[0:7], err) } - nlh := ns.NlHandle() - // Set the container interface and its peer MTU to 1450 to allow // for 50 bytes vxlan encap (inner eth header(14) + outer IP(20) + // outer UDP(8) + vxlan header(8)) diff --git a/vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_network.go b/vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_network.go index 7edb5077c5..cc2f0879a0 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_network.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_network.go @@ -284,7 +284,7 @@ func populateVNITbl() { } defer ns.Close() - nlh, err := netlink.NewHandleAt(ns) + nlh, err := netlink.NewHandleAt(ns, syscall.NETLINK_ROUTE) if err != nil { logrus.Errorf("Could not open netlink handle during vni population for ns %s: %v", path, err) return nil diff --git a/vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_utils.go b/vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_utils.go index f9f32dec48..f49c5d4e5f 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_utils.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_utils.go @@ -3,6 +3,7 @@ package overlay import ( "fmt" "strings" + "syscall" "github.com/Sirupsen/logrus" "github.com/docker/libnetwork/netutils" @@ -128,7 +129,7 @@ func deleteVxlanByVNI(path string, vni uint32) error { } defer ns.Close() - nlh, err = netlink.NewHandleAt(ns) + nlh, err = netlink.NewHandleAt(ns, syscall.NETLINK_ROUTE) if err != nil { return fmt.Errorf("failed to get netlink handle for ns %s: %v", path, err) } diff --git a/vendor/src/github.com/docker/libnetwork/drivers/overlay/overlay.go b/vendor/src/github.com/docker/libnetwork/drivers/overlay/overlay.go index 7c5d6d548b..f7e1ccc77a 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/overlay/overlay.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/overlay/overlay.go @@ -306,9 +306,9 @@ func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) } keys := make([]*key, 0, len(encrData.Keys)) for i := 0; i < len(encrData.Keys); i++ { - k, err := parseEncryptionKey(encrData.Keys[i], encrData.Tags[i]) - if err != nil { - return err + k := &key{ + value: encrData.Keys[i], + tag: uint32(encrData.Tags[i]), } keys = append(keys, k) } @@ -319,17 +319,23 @@ func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) if !ok { return fmt.Errorf("invalid encryption key notification data") } - newKey, err = parseEncryptionKey(encrData.Key, encrData.Tag) - if err != nil { - return err + if encrData.Key != nil { + newKey = &key{ + value: encrData.Key, + tag: uint32(encrData.Tag), + } } - priKey, err = parseEncryptionKey(encrData.Primary, encrData.PrimaryTag) - if err != nil { - return err + if encrData.Primary != nil { + priKey = &key{ + value: encrData.Primary, + tag: uint32(encrData.PrimaryTag), + } } - delKey, err = parseEncryptionKey(encrData.Prune, encrData.PruneTag) - if err != nil { - return err + if encrData.Prune != nil { + delKey = &key{ + value: encrData.Prune, + tag: uint32(encrData.PruneTag), + } } d.updateKeys(newKey, priKey, delKey) default: diff --git a/vendor/src/github.com/docker/libnetwork/networkdb/cluster.go b/vendor/src/github.com/docker/libnetwork/networkdb/cluster.go index d984c101f6..e8340401e5 100644 --- a/vendor/src/github.com/docker/libnetwork/networkdb/cluster.go +++ b/vendor/src/github.com/docker/libnetwork/networkdb/cluster.go @@ -3,6 +3,7 @@ package networkdb import ( "bytes" "crypto/rand" + "encoding/hex" "fmt" "math/big" rnd "math/rand" @@ -36,6 +37,7 @@ func (l *logWriter) Write(p []byte) (int, error) { // SetKey adds a new key to the key ring func (nDB *NetworkDB) SetKey(key []byte) { + logrus.Debugf("Adding key %s", hex.EncodeToString(key)[0:5]) for _, dbKey := range nDB.config.Keys { if bytes.Equal(key, dbKey) { return @@ -50,6 +52,7 @@ func (nDB *NetworkDB) SetKey(key []byte) { // SetPrimaryKey sets the given key as the primary key. This should have // been added apriori through SetKey func (nDB *NetworkDB) SetPrimaryKey(key []byte) { + logrus.Debugf("Primary Key %s", hex.EncodeToString(key)[0:5]) for _, dbKey := range nDB.config.Keys { if bytes.Equal(key, dbKey) { if nDB.keyring != nil { @@ -63,6 +66,7 @@ func (nDB *NetworkDB) SetPrimaryKey(key []byte) { // RemoveKey removes a key from the key ring. The key being removed // can't be the primary key func (nDB *NetworkDB) RemoveKey(key []byte) { + logrus.Debugf("Remove Key %s", hex.EncodeToString(key)[0:5]) for i, dbKey := range nDB.config.Keys { if bytes.Equal(key, dbKey) { nDB.config.Keys = append(nDB.config.Keys[:i], nDB.config.Keys[i+1:]...) @@ -90,6 +94,9 @@ func (nDB *NetworkDB) clusterInit() error { var err error if len(nDB.config.Keys) > 0 { + for i, key := range nDB.config.Keys { + logrus.Debugf("Encryption key %d: %s", i+1, hex.EncodeToString(key)[0:5]) + } nDB.keyring, err = memberlist.NewKeyring(nDB.config.Keys, nDB.config.Keys[0]) if err != nil { return err diff --git a/vendor/src/github.com/docker/libnetwork/ns/init_linux.go b/vendor/src/github.com/docker/libnetwork/ns/init_linux.go index ea0cfc0593..78529c7fbe 100644 --- a/vendor/src/github.com/docker/libnetwork/ns/init_linux.go +++ b/vendor/src/github.com/docker/libnetwork/ns/init_linux.go @@ -3,6 +3,8 @@ package ns import ( "fmt" "os" + "os/exec" + "strings" "sync" "syscall" @@ -24,7 +26,7 @@ func Init() { if err != nil { log.Errorf("could not get initial namespace: %v", err) } - initNl, err = netlink.NewHandle() + initNl, err = netlink.NewHandle(getSupportedNlFamilies()...) if err != nil { log.Errorf("could not create netlink handle on initial namespace: %v", err) } @@ -32,6 +34,7 @@ func Init() { // SetNamespace sets the initial namespace handler func SetNamespace() error { + initOnce.Do(Init) if err := netns.Set(initNs); err != nil { linkInfo, linkErr := getLink() if linkErr != nil { @@ -62,3 +65,22 @@ func NlHandle() *netlink.Handle { initOnce.Do(Init) return initNl } + +func getSupportedNlFamilies() []int { + fams := []int{syscall.NETLINK_ROUTE} + if err := loadXfrmModules(); err != nil { + log.Warnf("Could not load necessary modules for IPSEC rules: %v", err) + return fams + } + return append(fams, syscall.NETLINK_XFRM) +} + +func loadXfrmModules() error { + if out, err := exec.Command("modprobe", "-va", "xfrm_user").CombinedOutput(); err != nil { + return fmt.Errorf("Running modprobe xfrm_user failed with message: `%s`, error: %v", strings.TrimSpace(string(out)), err) + } + if out, err := exec.Command("modprobe", "-va", "xfrm_algo").CombinedOutput(); err != nil { + return fmt.Errorf("Running modprobe xfrm_algo failed with message: `%s`, error: %v", strings.TrimSpace(string(out)), err) + } + return nil +} diff --git a/vendor/src/github.com/docker/libnetwork/osl/interface_linux.go b/vendor/src/github.com/docker/libnetwork/osl/interface_linux.go index 63fcf5561d..5b537a4cb7 100644 --- a/vendor/src/github.com/docker/libnetwork/osl/interface_linux.go +++ b/vendor/src/github.com/docker/libnetwork/osl/interface_linux.go @@ -6,6 +6,7 @@ import ( "regexp" "sync" "syscall" + "time" log "github.com/Sirupsen/logrus" "github.com/docker/libnetwork/ns" @@ -290,7 +291,12 @@ func (n *networkNamespace) AddInterface(srcName, dstPrefix string, options ...If } // Up the interface. - if err := nlh.LinkSetUp(iface); err != nil { + cnt := 0 + for err = nlh.LinkSetUp(iface); err != nil && cnt < 3; cnt++ { + log.Debugf("retrying link setup because of: %v", err) + time.Sleep(10 * time.Millisecond) + } + if err != nil { return fmt.Errorf("failed to set link up: %v", err) } diff --git a/vendor/src/github.com/docker/libnetwork/osl/namespace_linux.go b/vendor/src/github.com/docker/libnetwork/osl/namespace_linux.go index b9a0201e16..3dad60472a 100644 --- a/vendor/src/github.com/docker/libnetwork/osl/namespace_linux.go +++ b/vendor/src/github.com/docker/libnetwork/osl/namespace_linux.go @@ -30,7 +30,6 @@ var ( gpmWg sync.WaitGroup gpmCleanupPeriod = 60 * time.Second gpmChan = make(chan chan struct{}) - nsOnce sync.Once ) // The networkNamespace type is the linux implementation of the Sandbox @@ -196,7 +195,7 @@ func NewSandbox(key string, osCreate, isRestore bool) (Sandbox, error) { } defer sboxNs.Close() - n.nlHandle, err = netlink.NewHandleAt(sboxNs) + n.nlHandle, err = netlink.NewHandleAt(sboxNs, syscall.NETLINK_ROUTE) if err != nil { return nil, fmt.Errorf("failed to create a netlink handle: %v", err) } @@ -238,7 +237,7 @@ func GetSandboxForExternalKey(basePath string, key string) (Sandbox, error) { } defer sboxNs.Close() - n.nlHandle, err = netlink.NewHandleAt(sboxNs) + n.nlHandle, err = netlink.NewHandleAt(sboxNs, syscall.NETLINK_ROUTE) if err != nil { return nil, fmt.Errorf("failed to create a netlink handle: %v", err) } @@ -326,7 +325,6 @@ func (n *networkNamespace) InvokeFunc(f func()) error { // InitOSContext initializes OS context while configuring network resources func InitOSContext() func() { - nsOnce.Do(ns.Init) runtime.LockOSThread() if err := ns.SetNamespace(); err != nil { log.Error(err) diff --git a/vendor/src/github.com/docker/libnetwork/resolver.go b/vendor/src/github.com/docker/libnetwork/resolver.go index 7566dcbf4e..597c55d861 100644 --- a/vendor/src/github.com/docker/libnetwork/resolver.go +++ b/vendor/src/github.com/docker/libnetwork/resolver.go @@ -62,6 +62,21 @@ type extDNSEntry struct { extOnce sync.Once } +type sboxQuery struct { + sboxID string + dnsID uint16 +} + +type clientConnGC struct { + toDelete bool + client clientConn +} + +var ( + queryGCMutex sync.Mutex + queryGC map[sboxQuery]*clientConnGC +) + // resolver implements the Resolver interface type resolver struct { sb *sandbox @@ -79,6 +94,21 @@ type resolver struct { func init() { rand.Seed(time.Now().Unix()) + queryGC = make(map[sboxQuery]*clientConnGC) + go func() { + ticker := time.NewTicker(1 * time.Minute) + for range ticker.C { + queryGCMutex.Lock() + for query, conn := range queryGC { + if !conn.toDelete { + conn.toDelete = true + continue + } + delete(queryGC, query) + } + queryGCMutex.Unlock() + } + }() } // NewResolver creates a new instance of the Resolver @@ -370,6 +400,7 @@ func (r *resolver) ServeDNS(w dns.ResponseWriter, query *dns.Msg) { writer = w } else { queryID := query.Id + extQueryLoop: for i := 0; i < maxExtDNS; i++ { extDNS := &r.extDNSList[i] if extDNS.ipStr == "" { @@ -435,14 +466,26 @@ func (r *resolver) ServeDNS(w dns.ResponseWriter, query *dns.Msg) { log.Debugf("Send to DNS server failed, %s", err) continue } + for { + // If a reply comes after a read timeout it will remain in the socket buffer + // and will be read after sending next query. To ignore such stale replies + // save the query context in a GC queue when read timesout. On the next reply + // if the context is present in the GC queue its a old reply. Ignore it and + // read again + resp, err = co.ReadMsg() + if err != nil { + if nerr, ok := err.(net.Error); ok && nerr.Timeout() { + r.addQueryToGC(w, query) + } + r.forwardQueryEnd(w, query) + log.Debugf("Read from DNS server failed, %s", err) + continue extQueryLoop + } - resp, err = co.ReadMsg() - if err != nil { - r.forwardQueryEnd(w, query) - log.Debugf("Read from DNS server failed, %s", err) - continue + if !r.checkRespInGC(w, resp) { + break + } } - // Retrieves the context for the forwarded query and returns the client connection // to send the reply to writer = r.forwardQueryEnd(w, resp) @@ -501,6 +544,49 @@ func (r *resolver) forwardQueryStart(w dns.ResponseWriter, msg *dns.Msg, queryID return true } +func (r *resolver) addQueryToGC(w dns.ResponseWriter, msg *dns.Msg) { + if w.LocalAddr().Network() != "udp" { + return + } + + r.queryLock.Lock() + cc, ok := r.client[msg.Id] + r.queryLock.Unlock() + if !ok { + return + } + + query := sboxQuery{ + sboxID: r.sb.ID(), + dnsID: msg.Id, + } + clientGC := &clientConnGC{ + client: cc, + } + queryGCMutex.Lock() + queryGC[query] = clientGC + queryGCMutex.Unlock() +} + +func (r *resolver) checkRespInGC(w dns.ResponseWriter, msg *dns.Msg) bool { + if w.LocalAddr().Network() != "udp" { + return false + } + + query := sboxQuery{ + sboxID: r.sb.ID(), + dnsID: msg.Id, + } + + queryGCMutex.Lock() + defer queryGCMutex.Unlock() + if _, ok := queryGC[query]; ok { + delete(queryGC, query) + return true + } + return false +} + func (r *resolver) forwardQueryEnd(w dns.ResponseWriter, msg *dns.Msg) dns.ResponseWriter { var ( cc clientConn From c355e059cc1a4f66338a039240195c66dc928e73 Mon Sep 17 00:00:00 2001 From: Alessandro Boch Date: Wed, 22 Jun 2016 09:44:56 -0700 Subject: [PATCH 3/3] Add modules for secure overlay network to check-config.sh Signed-off-by: Alessandro Boch --- contrib/check-config.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/contrib/check-config.sh b/contrib/check-config.sh index a328e73c61..c71c81930e 100755 --- a/contrib/check-config.sh +++ b/contrib/check-config.sh @@ -249,6 +249,8 @@ echo '- Network Drivers:' { echo '- "'$(wrap_color 'overlay' blue)'":' check_flags VXLAN | sed 's/^/ /' + echo ' Optional (for secure networks):' + check_flags XFRM_ALGO XFRM_USER | sed 's/^/ /' } | sed 's/^/ /' echo '- Storage Drivers:'