From b52748bb26371da036389094672c075990f508ae Mon Sep 17 00:00:00 2001 From: Alessandro Boch Date: Mon, 16 May 2016 10:21:50 -0700 Subject: [PATCH] Vendoring vishvananda/netlink f9bc7a684edbe780a09b87689db6cb1706bf327f Signed-off-by: Alessandro Boch --- libnetwork/Godeps/Godeps.json | 7 +- .../github.com/vishvananda/netlink/Makefile | 2 +- .../vishvananda/netlink/addr_linux.go | 188 ++++++++---- .../vishvananda/netlink/bpf_linux.go | 60 ++++ .../github.com/vishvananda/netlink/class.go | 12 +- .../vishvananda/netlink/class_linux.go | 64 +++- .../github.com/vishvananda/netlink/filter.go | 68 ++++- .../vishvananda/netlink/filter_linux.go | 225 ++++++++++---- .../github.com/vishvananda/netlink/handle.go | 86 ++++++ .../github.com/vishvananda/netlink/link.go | 34 ++- .../vishvananda/netlink/link_linux.go | 277 +++++++++++++---- .../vishvananda/netlink/neigh_linux.go | 51 +++- .../github.com/vishvananda/netlink/netlink.go | 2 +- .../vishvananda/netlink/nl/nl_linux.go | 64 +++- .../vishvananda/netlink/nl/tc_linux.go | 69 ++++- .../vishvananda/netlink/nl/xfrm_linux.go | 18 ++ .../netlink/nl/xfrm_state_linux.go | 33 ++- .../vishvananda/netlink/protinfo_linux.go | 8 +- .../github.com/vishvananda/netlink/qdisc.go | 47 +-- .../vishvananda/netlink/qdisc_linux.go | 55 +++- .../github.com/vishvananda/netlink/route.go | 8 +- .../vishvananda/netlink/route_linux.go | 48 ++- .../vishvananda/netlink/rule_linux.go | 24 +- .../github.com/vishvananda/netlink/xfrm.go | 10 + .../vishvananda/netlink/xfrm_policy.go | 14 + .../vishvananda/netlink/xfrm_policy_linux.go | 224 ++++++++++---- .../vishvananda/netlink/xfrm_state.go | 22 +- .../vishvananda/netlink/xfrm_state_linux.go | 278 +++++++++++++----- libnetwork/drivers/overlay/ov_utils.go | 3 +- 29 files changed, 1602 insertions(+), 399 deletions(-) create mode 100644 libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/bpf_linux.go create mode 100644 libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/handle.go diff --git a/libnetwork/Godeps/Godeps.json b/libnetwork/Godeps/Godeps.json index 7d2323ecda..46e0a16d10 100644 --- a/libnetwork/Godeps/Godeps.json +++ b/libnetwork/Godeps/Godeps.json @@ -1,7 +1,6 @@ { "ImportPath": "github.com/docker/libnetwork", - "GoVersion": "go1.5", - "GodepVersion": "v62", + "GoVersion": "go1.6", "Packages": [ "./..." ], @@ -384,11 +383,11 @@ }, { "ImportPath": "github.com/vishvananda/netlink", - "Rev": "631962935bff4f3d20ff32a72e8944f6d2836a26" + "Rev": "f9bc7a684edbe780a09b87689db6cb1706bf327f" }, { "ImportPath": "github.com/vishvananda/netlink/nl", - "Rev": "631962935bff4f3d20ff32a72e8944f6d2836a26" + "Rev": "f9bc7a684edbe780a09b87689db6cb1706bf327f" }, { "ImportPath": "github.com/vishvananda/netns", diff --git a/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/Makefile b/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/Makefile index 1b977de4de..75f3429836 100644 --- a/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/Makefile +++ b/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/Makefile @@ -11,7 +11,7 @@ goroot = $(addprefix ../../../,$(1)) unroot = $(subst ../../../,,$(1)) fmt = $(addprefix fmt-,$(1)) -all: fmt test +all: test $(call goroot,$(DEPS)): go get $(call unroot,$@) diff --git a/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/addr_linux.go b/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/addr_linux.go index 9e4f62f1d5..b5eec65052 100644 --- a/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/addr_linux.go +++ b/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/addr_linux.go @@ -2,6 +2,7 @@ package netlink import ( "fmt" + "log" "net" "strings" "syscall" @@ -15,24 +16,35 @@ const IFA_FLAGS = 0x8 // 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 { + return pkgHandle.AddrAdd(link, addr) +} - req := nl.NewNetlinkRequest(syscall.RTM_NEWADDR, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK) - return addrHandle(link, addr, req) +// AddrAdd will add an IP address to a link device. +// Equivalent to: `ip addr add $addr dev $link` +func (h *Handle) AddrAdd(link Link, addr *Addr) error { + req := h.newNetlinkRequest(syscall.RTM_NEWADDR, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK) + return h.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) + return pkgHandle.AddrDel(link, addr) } -func addrHandle(link Link, addr *Addr, req *nl.NetlinkRequest) error { +// AddrDel will delete an IP address from a link device. +// Equivalent to: `ip addr del $addr dev $link` +func (h *Handle) AddrDel(link Link, addr *Addr) error { + req := h.newNetlinkRequest(syscall.RTM_DELADDR, syscall.NLM_F_ACK) + return h.addrHandle(link, addr, req) +} + +func (h *Handle) 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) + h.ensureIndex(base) family := nl.GetIPFamily(addr.IP) @@ -57,10 +69,14 @@ func addrHandle(link Link, addr *Addr, req *nl.NetlinkRequest) error { req.AddData(addressData) if addr.Flags != 0 { - b := make([]byte, 4) - native.PutUint32(b, uint32(addr.Flags)) - flagsData := nl.NewRtAttr(IFA_FLAGS, b) - req.AddData(flagsData) + if addr.Flags <= 0xff { + msg.IfAddrmsg.Flags = uint8(addr.Flags) + } else { + b := make([]byte, 4) + native.PutUint32(b, uint32(addr.Flags)) + flagsData := nl.NewRtAttr(IFA_FLAGS, b) + req.AddData(flagsData) + } } if addr.Label != "" { @@ -76,7 +92,14 @@ func addrHandle(link Link, addr *Addr, req *nl.NetlinkRequest) error { // 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) + return pkgHandle.AddrList(link, family) +} + +// 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 (h *Handle) AddrList(link Link, family int) ([]Addr, error) { + req := h.newNetlinkRequest(syscall.RTM_GETADDR, syscall.NLM_F_DUMP) msg := nl.NewIfInfomsg(family) req.AddData(msg) @@ -85,62 +108,125 @@ func AddrList(link Link, family int) ([]Addr, error) { return nil, err } - index := 0 + indexFilter := 0 if link != nil { base := link.Attrs() - ensureIndex(base) - index = base.Index + h.ensureIndex(base) + indexFilter = base.Index } var res []Addr for _, m := range msgs { - msg := nl.DeserializeIfAddrmsg(m) + addr, msgFamily, ifindex, err := parseAddr(m) + if err != nil { + return res, err + } - if link != nil && msg.Index != uint32(index) { + if link != nil && ifindex != indexFilter { // Ignore messages from other interfaces continue } - if family != FAMILY_ALL && msg.Family != uint8(family) { + if family != FAMILY_ALL && msgFamily != family { continue } - attrs, err := nl.ParseRouteAttr(m[msg.Len():]) - if err != nil { - return nil, err - } - - var local, dst *net.IPNet - var addr Addr - for _, attr := range attrs { - switch attr.Attr.Type { - case syscall.IFA_ADDRESS: - dst = &net.IPNet{ - IP: attr.Value, - Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)), - } - case syscall.IFA_LOCAL: - local = &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]) - case IFA_FLAGS: - addr.Flags = int(native.Uint32(attr.Value[0:4])) - } - } - - // IFA_LOCAL should be there but if not, fall back to IFA_ADDRESS - if local != nil { - addr.IPNet = local - } else { - addr.IPNet = dst - } - addr.Scope = int(msg.Scope) - res = append(res, addr) } return res, nil } + +func parseAddr(m []byte) (addr Addr, family, index int, err error) { + msg := nl.DeserializeIfAddrmsg(m) + + family = -1 + index = -1 + + attrs, err1 := nl.ParseRouteAttr(m[msg.Len():]) + if err1 != nil { + err = err1 + return + } + + family = int(msg.Family) + index = int(msg.Index) + + var local, dst *net.IPNet + for _, attr := range attrs { + switch attr.Attr.Type { + case syscall.IFA_ADDRESS: + dst = &net.IPNet{ + IP: attr.Value, + Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)), + } + case syscall.IFA_LOCAL: + local = &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]) + case IFA_FLAGS: + addr.Flags = int(native.Uint32(attr.Value[0:4])) + } + } + + // IFA_LOCAL should be there but if not, fall back to IFA_ADDRESS + if local != nil { + addr.IPNet = local + } else { + addr.IPNet = dst + } + addr.Scope = int(msg.Scope) + + return +} + +type AddrUpdate struct { + LinkAddress net.IPNet + LinkIndex int + NewAddr bool // true=added false=deleted +} + +// AddrSubscribe takes a chan down which notifications will be sent +// when addresses change. Close the 'done' chan to stop subscription. +func AddrSubscribe(ch chan<- AddrUpdate, done <-chan struct{}) error { + s, err := nl.Subscribe(syscall.NETLINK_ROUTE, syscall.RTNLGRP_IPV4_IFADDR, syscall.RTNLGRP_IPV6_IFADDR) + if err != nil { + return err + } + if done != nil { + go func() { + <-done + s.Close() + }() + } + go func() { + defer close(ch) + for { + msgs, err := s.Receive() + if err != nil { + log.Printf("netlink.AddrSubscribe: Receive() error: %v", err) + return + } + for _, m := range msgs { + msgType := m.Header.Type + if msgType != syscall.RTM_NEWADDR && msgType != syscall.RTM_DELADDR { + log.Printf("netlink.AddrSubscribe: bad message type: %d", msgType) + continue + } + + addr, _, ifindex, err := parseAddr(m.Data) + if err != nil { + log.Printf("netlink.AddrSubscribe: could not parse address: %v", err) + continue + } + + ch <- AddrUpdate{LinkAddress: *addr.IPNet, LinkIndex: ifindex, NewAddr: msgType == syscall.RTM_NEWADDR} + } + } + }() + + return nil +} diff --git a/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/bpf_linux.go b/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/bpf_linux.go new file mode 100644 index 0000000000..acd9490131 --- /dev/null +++ b/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/bpf_linux.go @@ -0,0 +1,60 @@ +package netlink + +/* +#include +#include +#include +#include +#include +#include + +static int load_simple_bpf(int prog_type) { +#ifdef __NR_bpf + // { return 1; } + __u64 __attribute__((aligned(8))) insns[] = { + 0x00000001000000b7ull, + 0x0000000000000095ull, + }; + __u8 __attribute__((aligned(8))) license[] = "ASL2"; + // Copied from a header file since libc is notoriously slow to update. + // The call will succeed or fail and that will be our indication on + // whether or not it is supported. + struct { + __u32 prog_type; + __u32 insn_cnt; + __u64 insns; + __u64 license; + __u32 log_level; + __u32 log_size; + __u64 log_buf; + __u32 kern_version; + } __attribute__((aligned(8))) attr = { + .prog_type = prog_type, + .insn_cnt = 2, + .insns = (uintptr_t)&insns, + .license = (uintptr_t)&license, + }; + return syscall(__NR_bpf, 5, &attr, sizeof(attr)); +#else + errno = EINVAL; + return -1; +#endif +} +*/ +import "C" + +type BpfProgType C.int + +const ( + BPF_PROG_TYPE_UNSPEC BpfProgType = iota + BPF_PROG_TYPE_SOCKET_FILTER + BPF_PROG_TYPE_KPROBE + BPF_PROG_TYPE_SCHED_CLS + BPF_PROG_TYPE_SCHED_ACT +) + +// loadSimpleBpf loads a trivial bpf program for testing purposes +func loadSimpleBpf(progType BpfProgType) (int, error) { + fd, err := C.load_simple_bpf(C.int(progType)) + return int(fd), err +} diff --git a/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/class.go b/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/class.go index 264e3ad003..4577304100 100644 --- a/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/class.go +++ b/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/class.go @@ -9,7 +9,7 @@ type Class interface { Type() string } -// Class represents a netlink class. A filter is associated with a link, +// ClassAttrs represents a netlink class. A filter is associated with a link, // has a handle and a parent. The root filter of a device should have a // parent == HANDLE_ROOT. type ClassAttrs struct { @@ -20,7 +20,7 @@ type ClassAttrs struct { } func (q ClassAttrs) String() string { - return fmt.Sprintf("{LinkIndex: %d, Handle: %s, Parent: %s, Leaf: %s}", q.LinkIndex, HandleStr(q.Handle), HandleStr(q.Parent), q.Leaf) + return fmt.Sprintf("{LinkIndex: %d, Handle: %s, Parent: %s, Leaf: %d}", q.LinkIndex, HandleStr(q.Handle), HandleStr(q.Parent), q.Leaf) } type HtbClassAttrs struct { @@ -38,7 +38,7 @@ func (q HtbClassAttrs) String() string { return fmt.Sprintf("{Rate: %d, Ceil: %d, Buffer: %d, Cbuffer: %d}", q.Rate, q.Ceil, q.Buffer, q.Cbuffer) } -// Htb class +// HtbClass represents an Htb class type HtbClass struct { ClassAttrs Rate uint64 @@ -87,11 +87,11 @@ func (q HtbClass) String() string { return fmt.Sprintf("{Rate: %d, Ceil: %d, Buffer: %d, Cbuffer: %d}", q.Rate, q.Ceil, q.Buffer, q.Cbuffer) } -func (class *HtbClass) Attrs() *ClassAttrs { - return &class.ClassAttrs +func (q *HtbClass) Attrs() *ClassAttrs { + return &q.ClassAttrs } -func (class *HtbClass) Type() string { +func (q *HtbClass) Type() string { return "htb" } diff --git a/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/class_linux.go b/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/class_linux.go index 4a52d2b997..be62abd9cb 100644 --- a/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/class_linux.go +++ b/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/class_linux.go @@ -10,15 +10,27 @@ import ( // ClassDel will delete a class from the system. // Equivalent to: `tc class del $class` func ClassDel(class Class) error { - return classModify(syscall.RTM_DELTCLASS, 0, class) + return pkgHandle.ClassDel(class) +} + +// ClassDel will delete a class from the system. +// Equivalent to: `tc class del $class` +func (h *Handle) ClassDel(class Class) error { + return h.classModify(syscall.RTM_DELTCLASS, 0, class) } // ClassChange will change a class in place // Equivalent to: `tc class change $class` // The parent and handle MUST NOT be changed. - func ClassChange(class Class) error { - return classModify(syscall.RTM_NEWTCLASS, 0, class) + return pkgHandle.ClassChange(class) +} + +// ClassChange will change a class in place +// Equivalent to: `tc class change $class` +// The parent and handle MUST NOT be changed. +func (h *Handle) ClassChange(class Class) error { + return h.classModify(syscall.RTM_NEWTCLASS, 0, class) } // ClassReplace will replace a class to the system. @@ -27,21 +39,36 @@ func ClassChange(class Class) error { // If a class already exist with this parent/handle pair, the class is changed. // If a class does not already exist with this parent/handle, a new class is created. func ClassReplace(class Class) error { - return classModify(syscall.RTM_NEWTCLASS, syscall.NLM_F_CREATE, class) + return pkgHandle.ClassReplace(class) +} + +// ClassReplace will replace a class to the system. +// quivalent to: `tc class replace $class` +// The handle MAY be changed. +// If a class already exist with this parent/handle pair, the class is changed. +// If a class does not already exist with this parent/handle, a new class is created. +func (h *Handle) ClassReplace(class Class) error { + return h.classModify(syscall.RTM_NEWTCLASS, syscall.NLM_F_CREATE, class) } // ClassAdd will add a class to the system. // Equivalent to: `tc class add $class` func ClassAdd(class Class) error { - return classModify( + return pkgHandle.ClassAdd(class) +} + +// ClassAdd will add a class to the system. +// Equivalent to: `tc class add $class` +func (h *Handle) ClassAdd(class Class) error { + return h.classModify( syscall.RTM_NEWTCLASS, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL, class, ) } -func classModify(cmd, flags int, class Class) error { - req := nl.NewNetlinkRequest(cmd, flags|syscall.NLM_F_ACK) +func (h *Handle) classModify(cmd, flags int, class Class) error { + req := h.newNetlinkRequest(cmd, flags|syscall.NLM_F_ACK) base := class.Attrs() msg := &nl.TcMsg{ Family: nl.FAMILY_ALL, @@ -73,20 +100,20 @@ func classPayload(req *nl.NetlinkRequest, class Class) error { opt.Prio = htb.Prio // TODO: Handle Debug properly. For now default to 0 /* Calculate {R,C}Tab and set Rate and Ceil */ - cell_log := -1 - ccell_log := -1 + cellLog := -1 + ccellLog := -1 linklayer := nl.LINKLAYER_ETHERNET mtu := 1600 var rtab [256]uint32 var ctab [256]uint32 tcrate := nl.TcRateSpec{Rate: uint32(htb.Rate)} - if CalcRtable(&tcrate, rtab, cell_log, uint32(mtu), linklayer) < 0 { - return errors.New("HTB: failed to calculate rate table.") + if CalcRtable(&tcrate, rtab, cellLog, uint32(mtu), linklayer) < 0 { + return errors.New("HTB: failed to calculate rate table") } opt.Rate = tcrate tcceil := nl.TcRateSpec{Rate: uint32(htb.Ceil)} - if CalcRtable(&tcceil, ctab, ccell_log, uint32(mtu), linklayer) < 0 { - return errors.New("HTB: failed to calculate ceil rate table.") + if CalcRtable(&tcceil, ctab, ccellLog, uint32(mtu), linklayer) < 0 { + return errors.New("HTB: failed to calculate ceil rate table") } opt.Ceil = tcceil nl.NewRtAttrChild(options, nl.TCA_HTB_PARMS, opt.Serialize()) @@ -101,14 +128,21 @@ func classPayload(req *nl.NetlinkRequest, class Class) error { // Equivalent to: `tc class show`. // Generally returns nothing if link and parent are not specified. func ClassList(link Link, parent uint32) ([]Class, error) { - req := nl.NewNetlinkRequest(syscall.RTM_GETTCLASS, syscall.NLM_F_DUMP) + return pkgHandle.ClassList(link, parent) +} + +// ClassList gets a list of classes in the system. +// Equivalent to: `tc class show`. +// Generally returns nothing if link and parent are not specified. +func (h *Handle) ClassList(link Link, parent uint32) ([]Class, error) { + req := h.newNetlinkRequest(syscall.RTM_GETTCLASS, syscall.NLM_F_DUMP) msg := &nl.TcMsg{ Family: nl.FAMILY_ALL, Parent: parent, } if link != nil { base := link.Attrs() - ensureIndex(base) + h.ensureIndex(base) msg.Ifindex = int32(base.Index) } req.AddData(msg) diff --git a/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/filter.go b/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/filter.go index 80ef34ded4..8d62ca55ef 100644 --- a/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/filter.go +++ b/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/filter.go @@ -11,7 +11,7 @@ type Filter interface { Type() string } -// Filter represents a netlink filter. A filter is associated with a link, +// FilterAttrs represents a netlink filter. A filter is associated with a link, // has a handle and a parent. The root filter of a device should have a // parent == HANDLE_ROOT. type FilterAttrs struct { @@ -26,11 +26,45 @@ func (q FilterAttrs) String() string { return fmt.Sprintf("{LinkIndex: %d, Handle: %s, Parent: %s, Priority: %d, Protocol: %d}", q.LinkIndex, HandleStr(q.Handle), HandleStr(q.Parent), q.Priority, q.Protocol) } +// Action represents an action in any supported filter. +type Action interface { + Type() string +} + +type BpfAction struct { + nl.TcActBpf + Fd int + Name string +} + +func (action *BpfAction) Type() string { + return "bpf" +} + +type MirredAction struct { + nl.TcMirred +} + +func (action *MirredAction) Type() string { + return "mirred" +} + +func NewMirredAction(redirIndex int) *MirredAction { + return &MirredAction{ + TcMirred: nl.TcMirred{ + TcGen: nl.TcGen{Action: nl.TC_ACT_STOLEN}, + Eaction: nl.TCA_EGRESS_REDIR, + Ifindex: uint32(redirIndex), + }, + } +} + // U32 filters on many packet related properties type U32 struct { FilterAttrs - // Currently only supports redirecting to another interface + ClassId uint32 RedirIndex int + Actions []Action } func (filter *U32) Attrs() *FilterAttrs { @@ -57,7 +91,7 @@ type FilterFwAttrs struct { LinkLayer int } -// FwFilter filters on firewall marks +// Fw filter filters on firewall marks type Fw struct { FilterAttrs ClassId uint32 @@ -73,8 +107,8 @@ type Fw struct { func NewFw(attrs FilterAttrs, fattrs FilterFwAttrs) (*Fw, error) { var rtab [256]uint32 var ptab [256]uint32 - rcell_log := -1 - pcell_log := -1 + rcellLog := -1 + pcellLog := -1 avrate := fattrs.AvRate / 8 police := nl.TcPolice{} police.Rate.Rate = fattrs.Rate / 8 @@ -90,8 +124,8 @@ func NewFw(attrs FilterAttrs, fattrs FilterFwAttrs) (*Fw, error) { if police.Rate.Rate != 0 { police.Rate.Mpu = fattrs.Mpu police.Rate.Overhead = fattrs.Overhead - if CalcRtable(&police.Rate, rtab, rcell_log, fattrs.Mtu, linklayer) < 0 { - return nil, errors.New("TBF: failed to calculate rate table.") + 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))) } @@ -99,8 +133,8 @@ func NewFw(attrs FilterAttrs, fattrs FilterFwAttrs) (*Fw, error) { if police.PeakRate.Rate != 0 { police.PeakRate.Mpu = fattrs.Mpu police.PeakRate.Overhead = fattrs.Overhead - if CalcRtable(&police.PeakRate, ptab, pcell_log, fattrs.Mtu, linklayer) < 0 { - return nil, errors.New("POLICE: failed to calculate peak rate table.") + if CalcRtable(&police.PeakRate, ptab, pcellLog, fattrs.Mtu, linklayer) < 0 { + return nil, errors.New("POLICE: failed to calculate peak rate table") } } @@ -124,6 +158,22 @@ func (filter *Fw) Type() string { return "fw" } +type BpfFilter struct { + FilterAttrs + ClassId uint32 + Fd int + Name string + DirectAction bool +} + +func (filter *BpfFilter) Type() string { + return "bpf" +} + +func (filter *BpfFilter) Attrs() *FilterAttrs { + return &filter.FilterAttrs +} + // GenericFilter filters represent types that are not currently understood // by this netlink library. type GenericFilter struct { diff --git a/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/filter_linux.go b/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/filter_linux.go index 1dc688b124..cf1e13d965 100644 --- a/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/filter_linux.go +++ b/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/filter_linux.go @@ -12,7 +12,13 @@ import ( // FilterDel will delete a filter from the system. // Equivalent to: `tc filter del $filter` func FilterDel(filter Filter) error { - req := nl.NewNetlinkRequest(syscall.RTM_DELTFILTER, syscall.NLM_F_ACK) + return pkgHandle.FilterDel(filter) +} + +// FilterDel will delete a filter from the system. +// Equivalent to: `tc filter del $filter` +func (h *Handle) FilterDel(filter Filter) error { + req := h.newNetlinkRequest(syscall.RTM_DELTFILTER, syscall.NLM_F_ACK) base := filter.Attrs() msg := &nl.TcMsg{ Family: nl.FAMILY_ALL, @@ -30,8 +36,14 @@ func FilterDel(filter Filter) error { // FilterAdd will add a filter to the system. // Equivalent to: `tc filter add $filter` func FilterAdd(filter Filter) error { + return pkgHandle.FilterAdd(filter) +} + +// FilterAdd will add a filter to the system. +// Equivalent to: `tc filter add $filter` +func (h *Handle) FilterAdd(filter Filter) error { native = nl.NativeEndian() - req := nl.NewNetlinkRequest(syscall.RTM_NEWTFILTER, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK) + req := h.newNetlinkRequest(syscall.RTM_NEWTFILTER, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK) base := filter.Attrs() msg := &nl.TcMsg{ Family: nl.FAMILY_ALL, @@ -52,17 +64,17 @@ func FilterAdd(filter Filter) error { } sel.Keys = append(sel.Keys, nl.TcU32Key{}) nl.NewRtAttrChild(options, nl.TCA_U32_SEL, sel.Serialize()) - actions := nl.NewRtAttrChild(options, nl.TCA_U32_ACT, nil) - table := nl.NewRtAttrChild(actions, nl.TCA_ACT_TAB, nil) - nl.NewRtAttrChild(table, nl.TCA_KIND, nl.ZeroTerminated("mirred")) - // redirect to other interface - mir := nl.TcMirred{ - Action: nl.TC_ACT_STOLEN, - Eaction: nl.TCA_EGRESS_REDIR, - Ifindex: uint32(u32.RedirIndex), + if u32.ClassId != 0 { + nl.NewRtAttrChild(options, nl.TCA_U32_CLASSID, nl.Uint32Attr(u32.ClassId)) + } + actionsAttr := nl.NewRtAttrChild(options, nl.TCA_U32_ACT, nil) + // backwards compatibility + if u32.RedirIndex != 0 { + u32.Actions = append([]Action{NewMirredAction(u32.RedirIndex)}, u32.Actions...) + } + if err := encodeActions(actionsAttr, u32.Actions); err != nil { + return err } - aopts := nl.NewRtAttrChild(table, nl.TCA_OPTIONS, nil) - nl.NewRtAttrChild(aopts, nl.TCA_MIRRED_PARMS, mir.Serialize()) } else if fw, ok := filter.(*Fw); ok { if fw.Mask != 0 { b := make([]byte, 4) @@ -90,6 +102,21 @@ func FilterAdd(filter Filter) error { native.PutUint32(b, fw.ClassId) nl.NewRtAttrChild(options, nl.TCA_FW_CLASSID, b) } + } else if bpf, ok := filter.(*BpfFilter); ok { + var bpfFlags uint32 + if bpf.ClassId != 0 { + nl.NewRtAttrChild(options, nl.TCA_BPF_CLASSID, nl.Uint32Attr(bpf.ClassId)) + } + if bpf.Fd >= 0 { + nl.NewRtAttrChild(options, nl.TCA_BPF_FD, nl.Uint32Attr((uint32(bpf.Fd)))) + } + if bpf.Name != "" { + nl.NewRtAttrChild(options, nl.TCA_BPF_NAME, nl.ZeroTerminated(bpf.Name)) + } + if bpf.DirectAction { + bpfFlags |= nl.TCA_BPF_FLAG_ACT_DIRECT + } + nl.NewRtAttrChild(options, nl.TCA_BPF_FLAGS, nl.Uint32Attr(bpfFlags)) } req.AddData(options) @@ -101,14 +128,21 @@ func FilterAdd(filter Filter) error { // Equivalent to: `tc filter show`. // Generally retunrs nothing if link and parent are not specified. func FilterList(link Link, parent uint32) ([]Filter, error) { - req := nl.NewNetlinkRequest(syscall.RTM_GETTFILTER, syscall.NLM_F_DUMP) + 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. +func (h *Handle) FilterList(link Link, parent uint32) ([]Filter, error) { + req := h.newNetlinkRequest(syscall.RTM_GETTFILTER, syscall.NLM_F_DUMP) msg := &nl.TcMsg{ Family: nl.FAMILY_ALL, Parent: parent, } if link != nil { base := link.Attrs() - ensureIndex(base) + h.ensureIndex(base) msg.Ifindex = int32(base.Index) } req.AddData(msg) @@ -147,26 +181,29 @@ func FilterList(link Link, parent uint32) ([]Filter, error) { filter = &U32{} case "fw": filter = &Fw{} + case "bpf": + filter = &BpfFilter{} default: filter = &GenericFilter{FilterType: filterType} } case nl.TCA_OPTIONS: + data, err := nl.ParseRouteAttr(attr.Value) + if err != nil { + return nil, err + } switch filterType { case "u32": - data, err := nl.ParseRouteAttr(attr.Value) - if err != nil { - return nil, err - } detailed, err = parseU32Data(filter, data) if err != nil { return nil, err } case "fw": - data, err := nl.ParseRouteAttr(attr.Value) + detailed, err = parseFwData(filter, data) if err != nil { return nil, err } - detailed, err = parseFwData(filter, data) + case "bpf": + detailed, err = parseBpfData(filter, data) if err != nil { return nil, err } @@ -183,6 +220,85 @@ func FilterList(link Link, parent uint32) ([]Filter, error) { return res, nil } +func encodeActions(attr *nl.RtAttr, actions []Action) error { + tabIndex := int(nl.TCA_ACT_TAB) + + for _, action := range actions { + switch action := action.(type) { + default: + return fmt.Errorf("unknown action type %s", action.Type()) + case *MirredAction: + table := nl.NewRtAttrChild(attr, tabIndex, nil) + tabIndex++ + nl.NewRtAttrChild(table, nl.TCA_ACT_KIND, nl.ZeroTerminated("mirred")) + aopts := nl.NewRtAttrChild(table, nl.TCA_ACT_OPTIONS, nil) + nl.NewRtAttrChild(aopts, nl.TCA_MIRRED_PARMS, action.Serialize()) + case *BpfAction: + table := nl.NewRtAttrChild(attr, tabIndex, nil) + tabIndex++ + nl.NewRtAttrChild(table, nl.TCA_ACT_KIND, nl.ZeroTerminated("bpf")) + aopts := nl.NewRtAttrChild(table, nl.TCA_ACT_OPTIONS, nil) + nl.NewRtAttrChild(aopts, nl.TCA_ACT_BPF_PARMS, action.Serialize()) + nl.NewRtAttrChild(aopts, nl.TCA_ACT_BPF_FD, nl.Uint32Attr(uint32(action.Fd))) + nl.NewRtAttrChild(aopts, nl.TCA_ACT_BPF_NAME, nl.ZeroTerminated(action.Name)) + } + } + return nil +} + +func parseActions(tables []syscall.NetlinkRouteAttr) ([]Action, error) { + var actions []Action + for _, table := range tables { + var action Action + var actionType string + aattrs, err := nl.ParseRouteAttr(table.Value) + if err != nil { + return nil, err + } + nextattr: + for _, aattr := range aattrs { + switch aattr.Attr.Type { + case nl.TCA_KIND: + actionType = string(aattr.Value[:len(aattr.Value)-1]) + // only parse if the action is mirred or bpf + switch actionType { + case "mirred": + action = &MirredAction{} + case "bpf": + action = &BpfAction{} + default: + break nextattr + } + case nl.TCA_OPTIONS: + adata, err := nl.ParseRouteAttr(aattr.Value) + if err != nil { + return nil, err + } + for _, adatum := range adata { + switch actionType { + case "mirred": + switch adatum.Attr.Type { + case nl.TCA_MIRRED_PARMS: + action.(*MirredAction).TcMirred = *nl.DeserializeTcMirred(adatum.Value) + } + case "bpf": + switch adatum.Attr.Type { + case nl.TCA_ACT_BPF_PARMS: + action.(*BpfAction).TcActBpf = *nl.DeserializeTcActBpf(adatum.Value) + case nl.TCA_ACT_BPF_FD: + action.(*BpfAction).Fd = int(native.Uint32(adatum.Value[0:4])) + case nl.TCA_ACT_BPF_NAME: + action.(*BpfAction).Name = string(adatum.Value[:len(adatum.Value)-1]) + } + } + } + } + } + actions = append(actions, action) + } + return actions, nil +} + func parseU32Data(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error) { native = nl.NativeEndian() u32 := filter.(*U32) @@ -197,34 +313,17 @@ func parseU32Data(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error) return detailed, nil } case nl.TCA_U32_ACT: - table, err := nl.ParseRouteAttr(datum.Value) + tables, err := nl.ParseRouteAttr(datum.Value) if err != nil { return detailed, err } - if len(table) != 1 || table[0].Attr.Type != nl.TCA_ACT_TAB { - return detailed, fmt.Errorf("Action table not formed properly") + u32.Actions, err = parseActions(tables) + if err != nil { + return detailed, err } - aattrs, err := nl.ParseRouteAttr(table[0].Value) - for _, aattr := range aattrs { - switch aattr.Attr.Type { - case nl.TCA_KIND: - actionType := string(aattr.Value[:len(aattr.Value)-1]) - // only parse if the action is mirred - if actionType != "mirred" { - return detailed, nil - } - case nl.TCA_OPTIONS: - adata, err := nl.ParseRouteAttr(aattr.Value) - if err != nil { - return detailed, err - } - for _, adatum := range adata { - switch adatum.Attr.Type { - case nl.TCA_MIRRED_PARMS: - mir := nl.DeserializeTcMirred(adatum.Value) - u32.RedirIndex = int(mir.Ifindex) - } - } + for _, action := range u32.Actions { + if action, ok := action.(*MirredAction); ok { + u32.RedirIndex = int(action.Ifindex) } } } @@ -261,6 +360,28 @@ func parseFwData(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error) { return detailed, nil } +func parseBpfData(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error) { + native = nl.NativeEndian() + bpf := filter.(*BpfFilter) + detailed := true + for _, datum := range data { + switch datum.Attr.Type { + case nl.TCA_BPF_FD: + bpf.Fd = int(native.Uint32(datum.Value[0:4])) + case nl.TCA_BPF_NAME: + bpf.Name = string(datum.Value[:len(datum.Value)-1]) + case nl.TCA_BPF_CLASSID: + bpf.ClassId = native.Uint32(datum.Value[0:4]) + case nl.TCA_BPF_FLAGS: + flags := native.Uint32(datum.Value[0:4]) + if (flags & nl.TCA_BPF_FLAG_ACT_DIRECT) != 0 { + bpf.DirectAction = true + } + } + } + return detailed, nil +} + func AlignToAtm(size uint) uint { var linksize, cells int cells = int(size / nl.ATM_CELL_PAYLOAD) @@ -283,27 +404,27 @@ func AdjustSize(sz uint, mpu uint, linklayer int) uint { } } -func CalcRtable(rate *nl.TcRateSpec, rtab [256]uint32, cell_log int, mtu uint32, linklayer int) int { +func CalcRtable(rate *nl.TcRateSpec, rtab [256]uint32, cellLog int, mtu uint32, linklayer int) int { bps := rate.Rate mpu := rate.Mpu var sz uint if mtu == 0 { mtu = 2047 } - if cell_log < 0 { - cell_log = 0 - for (mtu >> uint(cell_log)) > 255 { - cell_log++ + if cellLog < 0 { + cellLog = 0 + for (mtu >> uint(cellLog)) > 255 { + cellLog++ } } for i := 0; i < 256; i++ { - sz = AdjustSize(uint((i+1)< 0 { - nl.NewRtAttrChild(data, nl.IFLA_VXLAN_PORT, nl.Uint16Attr(uint16(vxlan.Port))) + nl.NewRtAttrChild(data, nl.IFLA_VXLAN_PORT, htons(uint16(vxlan.Port))) } if vxlan.PortLow > 0 || vxlan.PortHigh > 0 { pr := vxlanPortRange{uint16(vxlan.PortLow), uint16(vxlan.PortHigh)} @@ -434,9 +525,16 @@ func addBondAttrs(bond *Bond, linkInfo *nl.RtAttr) { } // LinkAdd adds a new link device. The type and features of the device -// are taken fromt the parameters in the link object. +// are taken from the parameters in the link object. // Equivalent to: `ip link add $link` func LinkAdd(link Link) error { + return pkgHandle.LinkAdd(link) +} + +// 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 (h *Handle) LinkAdd(link Link) error { // TODO: set mtu and hardware address // TODO: support extra data for macvlan base := link.Attrs() @@ -473,17 +571,17 @@ func LinkAdd(link Link) error { if errno != 0 { return fmt.Errorf("Tuntap IOCTL TUNSETPERSIST failed, errno %v", errno) } - ensureIndex(base) + h.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 h.LinkSetMasterByIndex(link, base.MasterIndex) } return nil } - req := nl.NewNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK) + req := h.newNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK) msg := nl.NewIfInfomsg(syscall.AF_UNSPEC) // TODO: make it shorter @@ -588,12 +686,12 @@ func LinkAdd(link Link) error { return err } - ensureIndex(base) + h.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 h.LinkSetMasterByIndex(link, base.MasterIndex) } return nil } @@ -602,11 +700,18 @@ func LinkAdd(link Link) error { // the link object for it to be deleted. The other values are ignored. // Equivalent to: `ip link del $link` func LinkDel(link Link) error { + return pkgHandle.LinkDel(link) +} + +// 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 (h *Handle) LinkDel(link Link) error { base := link.Attrs() - ensureIndex(base) + h.ensureIndex(base) - req := nl.NewNetlinkRequest(syscall.RTM_DELLINK, syscall.NLM_F_ACK) + req := h.newNetlinkRequest(syscall.RTM_DELLINK, syscall.NLM_F_ACK) msg := nl.NewIfInfomsg(syscall.AF_UNSPEC) msg.Index = int32(base.Index) @@ -616,8 +721,8 @@ func LinkDel(link Link) error { return err } -func linkByNameDump(name string) (Link, error) { - links, err := LinkList() +func (h *Handle) linkByNameDump(name string) (Link, error) { + links, err := h.LinkList() if err != nil { return nil, err } @@ -630,8 +735,8 @@ func linkByNameDump(name string) (Link, error) { return nil, fmt.Errorf("Link %s not found", name) } -func linkByAliasDump(alias string) (Link, error) { - links, err := LinkList() +func (h *Handle) linkByAliasDump(alias string) (Link, error) { + links, err := h.LinkList() if err != nil { return nil, err } @@ -646,11 +751,16 @@ func linkByAliasDump(alias string) (Link, error) { // LinkByName finds a link by name and returns a pointer to the object. func LinkByName(name string) (Link, error) { - if lookupByDump { - return linkByNameDump(name) + return pkgHandle.LinkByName(name) +} + +// LinkByName finds a link by name and returns a pointer to the object. +func (h *Handle) LinkByName(name string) (Link, error) { + if h.lookupByDump { + return h.linkByNameDump(name) } - req := nl.NewNetlinkRequest(syscall.RTM_GETLINK, syscall.NLM_F_ACK) + req := h.newNetlinkRequest(syscall.RTM_GETLINK, syscall.NLM_F_ACK) msg := nl.NewIfInfomsg(syscall.AF_UNSPEC) req.AddData(msg) @@ -662,8 +772,8 @@ func LinkByName(name string) (Link, error) { 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) + h.lookupByDump = true + return h.linkByNameDump(name) } return link, err @@ -672,11 +782,17 @@ func LinkByName(name string) (Link, error) { // LinkByAlias finds a link by its alias and returns a pointer to the object. // If there are multiple links with the alias it returns the first one func LinkByAlias(alias string) (Link, error) { - if lookupByDump { - return linkByAliasDump(alias) + return pkgHandle.LinkByAlias(alias) +} + +// LinkByAlias finds a link by its alias and returns a pointer to the object. +// If there are multiple links with the alias it returns the first one +func (h *Handle) LinkByAlias(alias string) (Link, error) { + if h.lookupByDump { + return h.linkByAliasDump(alias) } - req := nl.NewNetlinkRequest(syscall.RTM_GETLINK, syscall.NLM_F_ACK) + req := h.newNetlinkRequest(syscall.RTM_GETLINK, syscall.NLM_F_ACK) msg := nl.NewIfInfomsg(syscall.AF_UNSPEC) req.AddData(msg) @@ -688,8 +804,8 @@ func LinkByAlias(alias string) (Link, error) { if err == syscall.EINVAL { // older kernels don't support looking up via IFLA_IFALIAS // so fall back to dumping all links - lookupByDump = true - return linkByAliasDump(alias) + h.lookupByDump = true + return h.linkByAliasDump(alias) } return link, err @@ -697,7 +813,12 @@ func LinkByAlias(alias string) (Link, error) { // 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) + return pkgHandle.LinkByIndex(index) +} + +// LinkByIndex finds a link by index and returns a pointer to the object. +func (h *Handle) LinkByIndex(index int) (Link, error) { + req := h.newNetlinkRequest(syscall.RTM_GETLINK, syscall.NLM_F_ACK) msg := nl.NewIfInfomsg(syscall.AF_UNSPEC) msg.Index = int32(index) @@ -824,6 +945,8 @@ func linkDeserialize(m []byte) (Link, error) { base.TxQLen = int(native.Uint32(attr.Value[0:4])) case syscall.IFLA_IFALIAS: base.Alias = string(attr.Value[:len(attr.Value)-1]) + case syscall.IFLA_STATS: + base.Statistics = parseLinkStats(attr.Value[:]) } } // Links that don't have IFLA_INFO_KIND are hardware devices @@ -838,9 +961,15 @@ func linkDeserialize(m []byte) (Link, error) { // LinkList gets a list of link devices. // Equivalent to: `ip link show` func LinkList() ([]Link, error) { + return pkgHandle.LinkList() +} + +// LinkList gets a list of link devices. +// Equivalent to: `ip link show` +func (h *Handle) 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) + req := h.newNetlinkRequest(syscall.RTM_GETLINK, syscall.NLM_F_DUMP) msg := nl.NewIfInfomsg(syscall.AF_UNSPEC) req.AddData(msg) @@ -904,33 +1033,57 @@ func LinkSubscribe(ch chan<- LinkUpdate, done <-chan struct{}) error { } func LinkSetHairpin(link Link, mode bool) error { - return setProtinfoAttr(link, mode, nl.IFLA_BRPORT_MODE) + return pkgHandle.LinkSetHairpin(link, mode) +} + +func (h *Handle) LinkSetHairpin(link Link, mode bool) error { + return h.setProtinfoAttr(link, mode, nl.IFLA_BRPORT_MODE) } func LinkSetGuard(link Link, mode bool) error { - return setProtinfoAttr(link, mode, nl.IFLA_BRPORT_GUARD) + return pkgHandle.LinkSetGuard(link, mode) +} + +func (h *Handle) LinkSetGuard(link Link, mode bool) error { + return h.setProtinfoAttr(link, mode, nl.IFLA_BRPORT_GUARD) } func LinkSetFastLeave(link Link, mode bool) error { - return setProtinfoAttr(link, mode, nl.IFLA_BRPORT_FAST_LEAVE) + return pkgHandle.LinkSetFastLeave(link, mode) +} + +func (h *Handle) LinkSetFastLeave(link Link, mode bool) error { + return h.setProtinfoAttr(link, mode, nl.IFLA_BRPORT_FAST_LEAVE) } func LinkSetLearning(link Link, mode bool) error { - return setProtinfoAttr(link, mode, nl.IFLA_BRPORT_LEARNING) + return pkgHandle.LinkSetLearning(link, mode) +} + +func (h *Handle) LinkSetLearning(link Link, mode bool) error { + return h.setProtinfoAttr(link, mode, nl.IFLA_BRPORT_LEARNING) } func LinkSetRootBlock(link Link, mode bool) error { - return setProtinfoAttr(link, mode, nl.IFLA_BRPORT_PROTECT) + return pkgHandle.LinkSetRootBlock(link, mode) +} + +func (h *Handle) LinkSetRootBlock(link Link, mode bool) error { + return h.setProtinfoAttr(link, mode, nl.IFLA_BRPORT_PROTECT) } func LinkSetFlood(link Link, mode bool) error { - return setProtinfoAttr(link, mode, nl.IFLA_BRPORT_UNICAST_FLOOD) + return pkgHandle.LinkSetFlood(link, mode) } -func setProtinfoAttr(link Link, mode bool, attr int) error { +func (h *Handle) LinkSetFlood(link Link, mode bool) error { + return h.setProtinfoAttr(link, mode, nl.IFLA_BRPORT_UNICAST_FLOOD) +} + +func (h *Handle) setProtinfoAttr(link Link, mode bool, attr int) error { base := link.Attrs() - ensureIndex(base) - req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK) + h.ensureIndex(base) + req := h.newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK) msg := nl.NewIfInfomsg(syscall.AF_BRIDGE) msg.Index = int32(base.Index) @@ -996,7 +1149,7 @@ func parseVxlanData(link Link, data []syscall.NetlinkRouteAttr) { 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])) + vxlan.Port = int(ntohs(datum.Value[0:2])) case nl.IFLA_VXLAN_PORT_RANGE: buf := bytes.NewBuffer(datum.Value[0:4]) var pr vxlanPortRange @@ -1211,3 +1364,7 @@ func parseGretapData(link Link, data []syscall.NetlinkRouteAttr) { } } } + +func parseLinkStats(data []byte) *LinkStatistics { + return (*LinkStatistics)(unsafe.Pointer(&data[0:SizeofLinkStats][0])) +} diff --git a/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/neigh_linux.go b/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/neigh_linux.go index 2af693bab9..9b6cd2c256 100644 --- a/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/neigh_linux.go +++ b/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/neigh_linux.go @@ -67,30 +67,62 @@ func (msg *Ndmsg) Len() int { // 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) + return pkgHandle.NeighAdd(neigh) +} + +// NeighAdd will add an IP to MAC mapping to the ARP table +// Equivalent to: `ip neigh add ....` +func (h *Handle) NeighAdd(neigh *Neigh) error { + return h.neighAdd(neigh, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL) } // NeighSet 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|syscall.NLM_F_REPLACE) + return pkgHandle.NeighSet(neigh) +} + +// NeighSet will add or replace an IP to MAC mapping to the ARP table +// Equivalent to: `ip neigh replace....` +func (h *Handle) NeighSet(neigh *Neigh) error { + return h.neighAdd(neigh, syscall.NLM_F_CREATE|syscall.NLM_F_REPLACE) } // 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) + return pkgHandle.NeighAppend(neigh) } +// NeighAppend will append an entry to FDB +// Equivalent to: `bridge fdb append...` +func (h *Handle) NeighAppend(neigh *Neigh) error { + return h.neighAdd(neigh, syscall.NLM_F_CREATE|syscall.NLM_F_APPEND) +} + +// NeighAppend will append an entry to FDB +// Equivalent to: `bridge fdb append...` func neighAdd(neigh *Neigh, mode int) error { - req := nl.NewNetlinkRequest(syscall.RTM_NEWNEIGH, mode|syscall.NLM_F_ACK) + return pkgHandle.neighAdd(neigh, mode) +} + +// NeighAppend will append an entry to FDB +// Equivalent to: `bridge fdb append...` +func (h *Handle) neighAdd(neigh *Neigh, mode int) error { + req := h.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 pkgHandle.NeighDel(neigh) +} + +// NeighDel will delete an IP address from a link device. +// Equivalent to: `ip addr del $addr dev $link` +func (h *Handle) NeighDel(neigh *Neigh) error { + req := h.newNetlinkRequest(syscall.RTM_DELNEIGH, syscall.NLM_F_ACK) return neighHandle(neigh, req) } @@ -130,7 +162,14 @@ func neighHandle(neigh *Neigh, req *nl.NetlinkRequest) error { // 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) + return pkgHandle.NeighList(linkIndex, family) +} + +// 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 (h *Handle) NeighList(linkIndex, family int) ([]Neigh, error) { + req := h.newNetlinkRequest(syscall.RTM_GETNEIGH, syscall.NLM_F_DUMP) msg := Ndmsg{ Family: uint8(family), Index: uint32(linkIndex), diff --git a/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/netlink.go b/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/netlink.go index 687d8760dd..deafb6cfa7 100644 --- a/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/netlink.go +++ b/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/netlink.go @@ -14,8 +14,8 @@ import ( "github.com/vishvananda/netlink/nl" ) +// Family type definitions const ( - // Family type definitions FAMILY_ALL = nl.FAMILY_ALL FAMILY_V4 = nl.FAMILY_V4 FAMILY_V6 = nl.FAMILY_V6 diff --git a/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/nl_linux.go b/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/nl_linux.go index e3afb5c232..1e5233b932 100644 --- a/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/nl_linux.go +++ b/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/nl_linux.go @@ -6,9 +6,12 @@ import ( "encoding/binary" "fmt" "net" + "runtime" "sync/atomic" "syscall" "unsafe" + + "github.com/vishvananda/netns" ) const ( @@ -171,7 +174,9 @@ func (a *RtAttr) Serialize() []byte { type NetlinkRequest struct { syscall.NlMsghdr - Data []NetlinkRequestData + Data []NetlinkRequestData + RouteSocket *NetlinkSocket + XfmrSocket *NetlinkSocket } // Serialize the Netlink Request into a byte array @@ -206,11 +211,29 @@ func (req *NetlinkRequest) AddData(data NetlinkRequestData) { // 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 + var ( + s *NetlinkSocket + 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) + } + + sharedSocket := s != nil + + if s == nil { + s, err = getNetlinkSocket(sockType) + if err != nil { + return nil, err + } + defer s.Close() } - defer s.Close() if err := s.Send(req); err != nil { return nil, err @@ -231,7 +254,10 @@ done: } for _, m := range msgs { if m.Header.Seq != req.Seq { - return nil, fmt.Errorf("Wrong Seq nr %d, expected 1", m.Header.Seq) + if sharedSocket { + continue + } + return nil, fmt.Errorf("Wrong Seq nr %d, expected %d", m.Header.Seq, req.Seq) } if m.Header.Pid != pid { return nil, fmt.Errorf("Wrong pid %d, expected %d", m.Header.Pid, pid) @@ -295,6 +321,32 @@ func getNetlinkSocket(protocol int) (*NetlinkSocket, error) { return s, nil } +// GetNetlinkSocketAt opens a netlink socket in the network namespace newNs +// and positions the thread back into the network namespace specified by curNs, +// when done. If curNs is close, the function derives the current namespace and +// moves back into it when done. If newNs is close, the socket will be opened +// in the current network namespace. +func GetNetlinkSocketAt(newNs, curNs netns.NsHandle, protocol int) (*NetlinkSocket, error) { + var err error + + if newNs.IsOpen() { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + if !curNs.IsOpen() { + if curNs, err = netns.Get(); err != nil { + return nil, fmt.Errorf("could not get current namespace while creating netlink socket: %v", err) + } + defer curNs.Close() + } + if err := netns.Set(newNs); err != nil { + return nil, fmt.Errorf("failed to set into network namespace %d while creating netlink socket: %v", newNs, err) + } + defer netns.Set(curNs) + } + + return getNetlinkSocket(protocol) +} + // 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 which Receive() method can be called diff --git a/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/tc_linux.go b/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/tc_linux.go index aa59005772..c6d85e951d 100644 --- a/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/tc_linux.go +++ b/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/tc_linux.go @@ -49,6 +49,15 @@ const ( TCAA_MAX = 1 ) +const ( + TCA_ACT_UNSPEC = iota + TCA_ACT_KIND + TCA_ACT_OPTIONS + TCA_ACT_INDEX + TCA_ACT_STATS + TCA_ACT_MAX +) + const ( TCA_PRIO_UNSPEC = iota TCA_PRIO_MQ @@ -69,6 +78,7 @@ const ( SizeofTcHtbGlob = 0x14 SizeofTcU32Key = 0x10 SizeofTcU32Sel = 0x10 // without keys + SizeofTcActBpf = 0x14 SizeofTcMirred = 0x1c SizeofTcPolice = 2*SizeofTcRateSpec + 0x20 ) @@ -533,9 +543,34 @@ const ( TC_ACT_STOLEN = 4 TC_ACT_QUEUED = 5 TC_ACT_REPEAT = 6 + TC_ACT_REDIRECT = 7 TC_ACT_JUMP = 0x10000000 ) +type TcGen struct { + Index uint32 + Capab uint32 + Action int32 + Refcnt int32 + Bindcnt int32 +} + +type TcActBpf struct { + TcGen +} + +func (msg *TcActBpf) Len() int { + return SizeofTcActBpf +} + +func DeserializeTcActBpf(b []byte) *TcActBpf { + return (*TcActBpf)(unsafe.Pointer(&b[0:SizeofTcActBpf][0])) +} + +func (x *TcActBpf) Serialize() []byte { + return (*(*[SizeofTcActBpf]byte)(unsafe.Pointer(x)))[:] +} + // #define tc_gen \ // __u32 index; \ // __u32 capab; \ @@ -549,11 +584,7 @@ const ( // }; type TcMirred struct { - Index uint32 - Capab uint32 - Action int32 - Refcnt int32 - Bindcnt int32 + TcGen Eaction int32 Ifindex uint32 } @@ -625,3 +656,31 @@ const ( TCA_FW_MASK TCA_FW_MAX = TCA_FW_MASK ) + +const ( + TCA_BPF_FLAG_ACT_DIRECT uint32 = 1 << iota +) + +const ( + TCA_BPF_UNSPEC = iota + TCA_BPF_ACT + TCA_BPF_POLICE + TCA_BPF_CLASSID + TCA_BPF_OPS_LEN + TCA_BPF_OPS + TCA_BPF_FD + TCA_BPF_NAME + TCA_BPF_FLAGS + TCA_BPF_MAX = TCA_BPF_FLAGS +) + +const ( + TCA_ACT_BPF_UNSPEC = iota + TCA_ACT_BPF_TM + TCA_ACT_BPF_PARMS + TCA_ACT_BPF_OPS_LEN + TCA_ACT_BPF_OPS + TCA_ACT_BPF_FD + TCA_ACT_BPF_NAME + TCA_ACT_BPF_MAX = TCA_ACT_BPF_NAME +) diff --git a/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/xfrm_linux.go b/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/xfrm_linux.go index d24637d278..ebf47946d6 100644 --- a/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/xfrm_linux.go +++ b/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/xfrm_linux.go @@ -78,6 +78,7 @@ const ( SizeofXfrmLifetimeCfg = 0x40 SizeofXfrmLifetimeCur = 0x20 SizeofXfrmId = 0x18 + SizeofXfrmMark = 0x08 ) // typedef union { @@ -256,3 +257,20 @@ func DeserializeXfrmId(b []byte) *XfrmId { func (msg *XfrmId) Serialize() []byte { return (*(*[SizeofXfrmId]byte)(unsafe.Pointer(msg)))[:] } + +type XfrmMark struct { + Value uint32 + Mask uint32 +} + +func (msg *XfrmMark) Len() int { + return SizeofXfrmMark +} + +func DeserializeXfrmMark(b []byte) *XfrmMark { + return (*XfrmMark)(unsafe.Pointer(&b[0:SizeofXfrmMark][0])) +} + +func (msg *XfrmMark) Serialize() []byte { + return (*(*[SizeofXfrmMark]byte)(unsafe.Pointer(msg)))[:] +} diff --git a/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/xfrm_state_linux.go b/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/xfrm_state_linux.go index 4876ce4583..482b4f37a0 100644 --- a/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/xfrm_state_linux.go +++ b/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/xfrm_state_linux.go @@ -5,12 +5,13 @@ import ( ) const ( - SizeofXfrmUsersaId = 0x18 - SizeofXfrmStats = 0x0c - SizeofXfrmUsersaInfo = 0xe0 - SizeofXfrmAlgo = 0x44 - SizeofXfrmAlgoAuth = 0x48 - SizeofXfrmEncapTmpl = 0x18 + SizeofXfrmUsersaId = 0x18 + SizeofXfrmStats = 0x0c + SizeofXfrmUsersaInfo = 0xe0 + SizeofXfrmAlgo = 0x44 + SizeofXfrmAlgoAuth = 0x48 + SizeofXfrmEncapTmpl = 0x18 + SizeofXfrmUsersaFlush = 0x8 ) // struct xfrm_usersa_id { @@ -219,3 +220,23 @@ func DeserializeXfrmEncapTmpl(b []byte) *XfrmEncapTmpl { func (msg *XfrmEncapTmpl) Serialize() []byte { return (*(*[SizeofXfrmEncapTmpl]byte)(unsafe.Pointer(msg)))[:] } + +// struct xfrm_usersa_flush { +// __u8 proto; +// }; + +type XfrmUsersaFlush struct { + Proto uint8 +} + +func (msg *XfrmUsersaFlush) Len() int { + return SizeofXfrmUsersaFlush +} + +func DeserializeXfrmUsersaFlush(b []byte) *XfrmUsersaFlush { + return (*XfrmUsersaFlush)(unsafe.Pointer(&b[0:SizeofXfrmUsersaFlush][0])) +} + +func (msg *XfrmUsersaFlush) Serialize() []byte { + return (*(*[SizeofXfrmUsersaFlush]byte)(unsafe.Pointer(msg)))[:] +} diff --git a/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/protinfo_linux.go b/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/protinfo_linux.go index 7181eba100..5b95d76486 100644 --- a/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/protinfo_linux.go +++ b/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/protinfo_linux.go @@ -8,10 +8,14 @@ import ( ) func LinkGetProtinfo(link Link) (Protinfo, error) { + return pkgHandle.LinkGetProtinfo(link) +} + +func (h *Handle) LinkGetProtinfo(link Link) (Protinfo, error) { base := link.Attrs() - ensureIndex(base) + h.ensureIndex(base) var pi Protinfo - req := nl.NewNetlinkRequest(syscall.RTM_GETLINK, syscall.NLM_F_DUMP) + req := h.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) diff --git a/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/qdisc.go b/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/qdisc.go index 48fe7c7981..3fb2bbae24 100644 --- a/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/qdisc.go +++ b/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/qdisc.go @@ -8,16 +8,21 @@ import ( const ( HANDLE_NONE = 0 HANDLE_INGRESS = 0xFFFFFFF1 + HANDLE_CLSACT = HANDLE_INGRESS HANDLE_ROOT = 0xFFFFFFFF PRIORITY_MAP_LEN = 16 ) +const ( + HANDLE_MIN_INGRESS = 0xFFFFFFF2 + HANDLE_MIN_EGRESS = 0xFFFFFFF3 +) type Qdisc interface { Attrs() *QdiscAttrs Type() string } -// Qdisc represents a netlink qdisc. A qdisc is associated with a link, +// QdiscAttrs represents a netlink qdisc. A qdisc is associated with a link, // has a handle, a parent and a refcnt. The root qdisc of a device should // have parent == HANDLE_ROOT. type QdiscAttrs struct { @@ -28,7 +33,7 @@ type QdiscAttrs struct { } func (q QdiscAttrs) String() string { - return fmt.Sprintf("{LinkIndex: %d, Handle: %s, Parent: %s, Refcnt: %s}", q.LinkIndex, HandleStr(q.Handle), HandleStr(q.Parent), q.Refcnt) + return fmt.Sprintf("{LinkIndex: %d, Handle: %s, Parent: %s, Refcnt: %d}", q.LinkIndex, HandleStr(q.Handle), HandleStr(q.Parent), q.Refcnt) } func MakeHandle(major, minor uint16) uint32 { @@ -149,7 +154,7 @@ type NetemQdiscAttrs struct { func (q NetemQdiscAttrs) String() string { return fmt.Sprintf( - "{Latency: %d, Limit: %d, Loss: %d, Gap: %d, Duplicate: %d, Jitter: %d}", + "{Latency: %d, Limit: %d, Loss: %f, Gap: %d, Duplicate: %f, Jitter: %d}", q.Latency, q.Limit, q.Loss, q.Gap, q.Duplicate, q.Jitter, ) } @@ -173,9 +178,9 @@ type Netem struct { func NewNetem(attrs QdiscAttrs, nattrs NetemQdiscAttrs) *Netem { var limit uint32 = 1000 - var loss_corr, delay_corr, duplicate_corr uint32 - var reorder_prob, reorder_corr uint32 - var corrupt_prob, corrupt_corr uint32 + var lossCorr, delayCorr, duplicateCorr uint32 + var reorderProb, reorderCorr uint32 + var corruptProb, corruptCorr uint32 latency := nattrs.Latency loss := Percentage2u32(nattrs.Loss) @@ -185,13 +190,13 @@ func NewNetem(attrs QdiscAttrs, nattrs NetemQdiscAttrs) *Netem { // Correlation if latency > 0 && jitter > 0 { - delay_corr = Percentage2u32(nattrs.DelayCorr) + delayCorr = Percentage2u32(nattrs.DelayCorr) } if loss > 0 { - loss_corr = Percentage2u32(nattrs.LossCorr) + lossCorr = Percentage2u32(nattrs.LossCorr) } if duplicate > 0 { - duplicate_corr = Percentage2u32(nattrs.DuplicateCorr) + duplicateCorr = Percentage2u32(nattrs.DuplicateCorr) } // FIXME should validate values(like loss/duplicate are percentages...) latency = time2Tick(latency) @@ -204,34 +209,34 @@ func NewNetem(attrs QdiscAttrs, nattrs NetemQdiscAttrs) *Netem { jitter = time2Tick(jitter) } - reorder_prob = Percentage2u32(nattrs.ReorderProb) - reorder_corr = Percentage2u32(nattrs.ReorderCorr) + reorderProb = Percentage2u32(nattrs.ReorderProb) + reorderCorr = Percentage2u32(nattrs.ReorderCorr) - if reorder_prob > 0 { + if reorderProb > 0 { // ERROR if lantency == 0 if gap == 0 { gap = 1 } } - corrupt_prob = Percentage2u32(nattrs.CorruptProb) - corrupt_corr = Percentage2u32(nattrs.CorruptCorr) + corruptProb = Percentage2u32(nattrs.CorruptProb) + corruptCorr = Percentage2u32(nattrs.CorruptCorr) return &Netem{ QdiscAttrs: attrs, Latency: latency, - DelayCorr: delay_corr, + DelayCorr: delayCorr, Limit: limit, Loss: loss, - LossCorr: loss_corr, + LossCorr: lossCorr, Gap: gap, Duplicate: duplicate, - DuplicateCorr: duplicate_corr, + DuplicateCorr: duplicateCorr, Jitter: jitter, - ReorderProb: reorder_prob, - ReorderCorr: reorder_corr, - CorruptProb: corrupt_prob, - CorruptCorr: corrupt_corr, + ReorderProb: reorderProb, + ReorderCorr: reorderCorr, + CorruptProb: corruptProb, + CorruptCorr: corruptCorr, } } diff --git a/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/qdisc_linux.go b/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/qdisc_linux.go index d9a8b170f5..62ac9d3dd8 100644 --- a/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/qdisc_linux.go +++ b/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/qdisc_linux.go @@ -13,21 +13,41 @@ import ( // QdiscDel will delete a qdisc from the system. // Equivalent to: `tc qdisc del $qdisc` func QdiscDel(qdisc Qdisc) error { - return qdiscModify(syscall.RTM_DELQDISC, 0, qdisc) + return pkgHandle.QdiscDel(qdisc) +} + +// QdiscDel will delete a qdisc from the system. +// Equivalent to: `tc qdisc del $qdisc` +func (h *Handle) QdiscDel(qdisc Qdisc) error { + return h.qdiscModify(syscall.RTM_DELQDISC, 0, qdisc) } // QdiscChange will change a qdisc in place // Equivalent to: `tc qdisc change $qdisc` // The parent and handle MUST NOT be changed. func QdiscChange(qdisc Qdisc) error { - return qdiscModify(syscall.RTM_NEWQDISC, 0, qdisc) + return pkgHandle.QdiscChange(qdisc) +} + +// QdiscChange will change a qdisc in place +// Equivalent to: `tc qdisc change $qdisc` +// The parent and handle MUST NOT be changed. +func (h *Handle) QdiscChange(qdisc Qdisc) error { + return h.qdiscModify(syscall.RTM_NEWQDISC, 0, qdisc) } // QdiscReplace will replace a qdisc to the system. // Equivalent to: `tc qdisc replace $qdisc` // The handle MUST change. func QdiscReplace(qdisc Qdisc) error { - return qdiscModify( + return pkgHandle.QdiscReplace(qdisc) +} + +// QdiscReplace will replace a qdisc to the system. +// Equivalent to: `tc qdisc replace $qdisc` +// The handle MUST change. +func (h *Handle) QdiscReplace(qdisc Qdisc) error { + return h.qdiscModify( syscall.RTM_NEWQDISC, syscall.NLM_F_CREATE|syscall.NLM_F_REPLACE, qdisc) @@ -36,14 +56,20 @@ func QdiscReplace(qdisc Qdisc) error { // QdiscAdd will add a qdisc to the system. // Equivalent to: `tc qdisc add $qdisc` func QdiscAdd(qdisc Qdisc) error { - return qdiscModify( + return pkgHandle.QdiscAdd(qdisc) +} + +// QdiscAdd will add a qdisc to the system. +// Equivalent to: `tc qdisc add $qdisc` +func (h *Handle) QdiscAdd(qdisc Qdisc) error { + return h.qdiscModify( syscall.RTM_NEWQDISC, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL, qdisc) } -func qdiscModify(cmd, flags int, qdisc Qdisc) error { - req := nl.NewNetlinkRequest(cmd, flags|syscall.NLM_F_ACK) +func (h *Handle) qdiscModify(cmd, flags int, qdisc Qdisc) error { + req := h.newNetlinkRequest(cmd, flags|syscall.NLM_F_ACK) base := qdisc.Attrs() msg := &nl.TcMsg{ Family: nl.FAMILY_ALL, @@ -139,11 +165,18 @@ func qdiscPayload(req *nl.NetlinkRequest, qdisc Qdisc) error { // Equivalent to: `tc qdisc show`. // The list can be filtered by link. func QdiscList(link Link) ([]Qdisc, error) { - req := nl.NewNetlinkRequest(syscall.RTM_GETQDISC, syscall.NLM_F_DUMP) + return pkgHandle.QdiscList(link) +} + +// QdiscList gets a list of qdiscs in the system. +// Equivalent to: `tc qdisc show`. +// The list can be filtered by link. +func (h *Handle) QdiscList(link Link) ([]Qdisc, error) { + req := h.newNetlinkRequest(syscall.RTM_GETQDISC, syscall.NLM_F_DUMP) index := int32(0) if link != nil { base := link.Attrs() - ensureIndex(base) + h.ensureIndex(base) index = int32(base.Index) } msg := &nl.TcMsg{ @@ -334,9 +367,9 @@ const ( ) var ( - tickInUsec float64 = 0.0 - clockFactor float64 = 0.0 - hz float64 = 0.0 + tickInUsec float64 + clockFactor float64 + hz float64 ) func initClock() { diff --git a/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/route.go b/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/route.go index a7303d4c22..aa869ea93c 100644 --- a/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/route.go +++ b/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/route.go @@ -41,8 +41,8 @@ type Route struct { } func (r Route) String() string { - return fmt.Sprintf("{Ifindex: %d Dst: %s Src: %s Gw: %s Flags: %s}", r.LinkIndex, r.Dst, - r.Src, r.Gw, r.ListFlags()) + 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) } func (r *Route) SetFlag(flag NextHopFlag) { @@ -59,8 +59,8 @@ type flagString struct { } var testFlags = []flagString{ - flagString{f: FLAG_ONLINK, s: "onlink"}, - flagString{f: FLAG_PERVASIVE, s: "pervasive"}, + {f: FLAG_ONLINK, s: "onlink"}, + {f: FLAG_PERVASIVE, s: "pervasive"}, } func (r *Route) ListFlags() []string { diff --git a/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/route_linux.go b/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/route_linux.go index d8026a7d1b..db952512e9 100644 --- a/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/route_linux.go +++ b/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/route_linux.go @@ -26,18 +26,30 @@ const ( // RouteAdd will add a route to the system. // Equivalent to: `ip route add $route` func RouteAdd(route *Route) error { - req := nl.NewNetlinkRequest(syscall.RTM_NEWROUTE, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK) - return routeHandle(route, req, nl.NewRtMsg()) + return pkgHandle.RouteAdd(route) +} + +// RouteAdd will add a route to the system. +// Equivalent to: `ip route add $route` +func (h *Handle) RouteAdd(route *Route) error { + req := h.newNetlinkRequest(syscall.RTM_NEWROUTE, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK) + return h.routeHandle(route, req, nl.NewRtMsg()) } // RouteDel will delete a route from the system. // Equivalent to: `ip route del $route` func RouteDel(route *Route) error { - req := nl.NewNetlinkRequest(syscall.RTM_DELROUTE, syscall.NLM_F_ACK) - return routeHandle(route, req, nl.NewRtDelMsg()) + return pkgHandle.RouteDel(route) } -func routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg) error { +// RouteDel will delete a route from the system. +// Equivalent to: `ip route del $route` +func (h *Handle) RouteDel(route *Route) error { + req := h.newNetlinkRequest(syscall.RTM_DELROUTE, syscall.NLM_F_ACK) + return h.routeHandle(route, req, nl.NewRtDelMsg()) +} + +func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg) error { if (route.Dst == nil || route.Dst.IP == nil) && route.Src == nil && route.Gw == nil { return fmt.Errorf("one of Dst.IP, Src, or Gw must not be nil") } @@ -116,6 +128,7 @@ func routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg) error { msg.Type = uint8(route.Type) } + msg.Flags = uint32(route.Flags) msg.Scope = uint8(route.Scope) msg.Family = uint8(family) req.AddData(msg) @@ -139,19 +152,32 @@ func routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg) error { // Equivalent to: `ip route show`. // The list can be filtered by link and ip family. func RouteList(link Link, family int) ([]Route, error) { + return pkgHandle.RouteList(link, family) +} + +// RouteList gets a list of routes in the system. +// Equivalent to: `ip route show`. +// The list can be filtered by link and ip family. +func (h *Handle) RouteList(link Link, family int) ([]Route, error) { var routeFilter *Route if link != nil { routeFilter = &Route{ LinkIndex: link.Attrs().Index, } } - return RouteListFiltered(family, routeFilter, RT_FILTER_OIF) + return h.RouteListFiltered(family, routeFilter, RT_FILTER_OIF) } // RouteListFiltered gets a list of routes in the system filtered with specified rules. // All rules must be defined in RouteFilter struct func RouteListFiltered(family int, filter *Route, filterMask uint64) ([]Route, error) { - req := nl.NewNetlinkRequest(syscall.RTM_GETROUTE, syscall.NLM_F_DUMP) + return pkgHandle.RouteListFiltered(family, filter, filterMask) +} + +// RouteListFiltered gets a list of routes in the system filtered with specified rules. +// All rules must be defined in RouteFilter struct +func (h *Handle) RouteListFiltered(family int, filter *Route, filterMask uint64) ([]Route, error) { + req := h.newNetlinkRequest(syscall.RTM_GETROUTE, syscall.NLM_F_DUMP) infmsg := nl.NewIfInfomsg(family) req.AddData(infmsg) @@ -257,7 +283,13 @@ func deserializeRoute(m []byte) (Route, error) { // RouteGet gets a route to a specific destination from the host system. // Equivalent to: 'ip route get'. func RouteGet(destination net.IP) ([]Route, error) { - req := nl.NewNetlinkRequest(syscall.RTM_GETROUTE, syscall.NLM_F_REQUEST) + return pkgHandle.RouteGet(destination) +} + +// RouteGet gets a route to a specific destination from the host system. +// Equivalent to: 'ip route get'. +func (h *Handle) RouteGet(destination net.IP) ([]Route, error) { + req := h.newNetlinkRequest(syscall.RTM_GETROUTE, syscall.NLM_F_REQUEST) family := nl.GetIPFamily(destination) var destinationData []byte var bitlen uint8 diff --git a/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/rule_linux.go b/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/rule_linux.go index ba84be00e7..8bce6666c9 100644 --- a/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/rule_linux.go +++ b/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/rule_linux.go @@ -11,14 +11,26 @@ import ( // RuleAdd adds a rule to the system. // Equivalent to: ip rule add func RuleAdd(rule *Rule) error { - req := nl.NewNetlinkRequest(syscall.RTM_NEWRULE, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK) + return pkgHandle.RuleAdd(rule) +} + +// RuleAdd adds a rule to the system. +// Equivalent to: ip rule add +func (h *Handle) RuleAdd(rule *Rule) error { + req := h.newNetlinkRequest(syscall.RTM_NEWRULE, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK) return ruleHandle(rule, req) } // RuleDel deletes a rule from the system. // Equivalent to: ip rule del func RuleDel(rule *Rule) error { - req := nl.NewNetlinkRequest(syscall.RTM_DELRULE, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK) + return pkgHandle.RuleDel(rule) +} + +// RuleDel deletes a rule from the system. +// Equivalent to: ip rule del +func (h *Handle) RuleDel(rule *Rule) error { + req := h.newNetlinkRequest(syscall.RTM_DELRULE, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK) return ruleHandle(rule, req) } @@ -128,7 +140,13 @@ func ruleHandle(rule *Rule, req *nl.NetlinkRequest) error { // RuleList lists rules in the system. // Equivalent to: ip rule list func RuleList(family int) ([]Rule, error) { - req := nl.NewNetlinkRequest(syscall.RTM_GETRULE, syscall.NLM_F_DUMP|syscall.NLM_F_REQUEST) + return pkgHandle.RuleList(family) +} + +// RuleList lists rules in the system. +// Equivalent to: ip rule list +func (h *Handle) RuleList(family int) ([]Rule, error) { + req := h.newNetlinkRequest(syscall.RTM_GETRULE, syscall.NLM_F_DUMP|syscall.NLM_F_REQUEST) msg := nl.NewIfInfomsg(family) req.AddData(msg) diff --git a/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm.go b/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm.go index 621ffb6c68..6ec40acac9 100644 --- a/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm.go +++ b/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm.go @@ -62,3 +62,13 @@ func (m Mode) String() string { } return fmt.Sprintf("%d", m) } + +// XfrmMark represents the mark associated to the state or policy +type XfrmMark struct { + Value uint32 + Mask uint32 +} + +func (m *XfrmMark) String() string { + return fmt.Sprintf("(0x%x,0x%x)", m.Value, m.Mask) +} diff --git a/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm_policy.go b/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm_policy.go index d85c65d2d2..26e0edda44 100644 --- a/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm_policy.go +++ b/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm_policy.go @@ -46,14 +46,28 @@ type XfrmPolicyTmpl struct { Reqid int } +func (t XfrmPolicyTmpl) String() string { + return fmt.Sprintf("{Dst: %v, Src: %v, Proto: %s, Mode: %s, Reqid: 0x%x}", + t.Dst, t.Src, t.Proto, t.Mode, t.Reqid) +} + // XfrmPolicy represents an ipsec policy. It represents the overlay network // and has a list of XfrmPolicyTmpls representing the base addresses of // the policy. type XfrmPolicy struct { Dst *net.IPNet Src *net.IPNet + Proto Proto + DstPort int + SrcPort int Dir Dir Priority int Index int + Mark *XfrmMark Tmpls []XfrmPolicyTmpl } + +func (p XfrmPolicy) String() string { + return fmt.Sprintf("{Dst: %v, Src: %v, Proto: %s, DstPort: %d, SrcPort: %d, Dir: %s, Priority: %d, Index: %d, Mark: %s, Tmpls: %s}", + p.Dst, p.Src, p.Proto, p.DstPort, p.SrcPort, p.Dir, p.Priority, p.Index, p.Mark, p.Tmpls) +} diff --git a/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm_policy_linux.go b/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm_policy_linux.go index 2daf6dc8b3..e21a41da07 100644 --- a/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm_policy_linux.go +++ b/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm_policy_linux.go @@ -7,19 +7,51 @@ import ( ) func selFromPolicy(sel *nl.XfrmSelector, policy *XfrmPolicy) { - sel.Family = uint16(nl.GetIPFamily(policy.Dst.IP)) - sel.Daddr.FromIP(policy.Dst.IP) - sel.Saddr.FromIP(policy.Src.IP) - prefixlenD, _ := policy.Dst.Mask.Size() - sel.PrefixlenD = uint8(prefixlenD) - prefixlenS, _ := policy.Src.Mask.Size() - sel.PrefixlenS = uint8(prefixlenS) + sel.Family = uint16(nl.FAMILY_V4) + if policy.Dst != nil { + sel.Family = uint16(nl.GetIPFamily(policy.Dst.IP)) + sel.Daddr.FromIP(policy.Dst.IP) + prefixlenD, _ := policy.Dst.Mask.Size() + sel.PrefixlenD = uint8(prefixlenD) + } + if policy.Src != nil { + sel.Saddr.FromIP(policy.Src.IP) + prefixlenS, _ := policy.Src.Mask.Size() + sel.PrefixlenS = uint8(prefixlenS) + } + sel.Proto = uint8(policy.Proto) + sel.Dport = nl.Swap16(uint16(policy.DstPort)) + sel.Sport = nl.Swap16(uint16(policy.SrcPort)) + sel.DportMask = ^uint16(0) + sel.SportMask = ^uint16(0) } // XfrmPolicyAdd will add an xfrm policy to the system. // Equivalent to: `ip xfrm policy add $policy` func XfrmPolicyAdd(policy *XfrmPolicy) error { - req := nl.NewNetlinkRequest(nl.XFRM_MSG_NEWPOLICY, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK) + return pkgHandle.XfrmPolicyAdd(policy) +} + +// XfrmPolicyAdd will add an xfrm policy to the system. +// Equivalent to: `ip xfrm policy add $policy` +func (h *Handle) XfrmPolicyAdd(policy *XfrmPolicy) error { + return h.xfrmPolicyAddOrUpdate(policy, nl.XFRM_MSG_NEWPOLICY) +} + +// XfrmPolicyUpdate will update an xfrm policy to the system. +// Equivalent to: `ip xfrm policy update $policy` +func XfrmPolicyUpdate(policy *XfrmPolicy) error { + return pkgHandle.XfrmPolicyUpdate(policy) +} + +// XfrmPolicyUpdate will update an xfrm policy to the system. +// Equivalent to: `ip xfrm policy update $policy` +func (h *Handle) XfrmPolicyUpdate(policy *XfrmPolicy) error { + return h.xfrmPolicyAddOrUpdate(policy, nl.XFRM_MSG_UPDPOLICY) +} + +func (h *Handle) xfrmPolicyAddOrUpdate(policy *XfrmPolicy, nlProto int) error { + req := h.newNetlinkRequest(nlProto, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK) msg := &nl.XfrmUserpolicyInfo{} selFromPolicy(&msg.Sel, policy) @@ -49,6 +81,10 @@ func XfrmPolicyAdd(policy *XfrmPolicy) error { tmpls := nl.NewRtAttr(nl.XFRMA_TMPL, tmplData) req.AddData(tmpls) } + if policy.Mark != nil { + out := nl.NewRtAttr(nl.XFRMA_MARK, writeMark(policy.Mark)) + req.AddData(out) + } _, err := req.Execute(syscall.NETLINK_XFRM, 0) return err @@ -58,15 +94,14 @@ func XfrmPolicyAdd(policy *XfrmPolicy) error { // the Tmpls are ignored when matching the policy to delete. // Equivalent to: `ip xfrm policy del $policy` func XfrmPolicyDel(policy *XfrmPolicy) error { - req := nl.NewNetlinkRequest(nl.XFRM_MSG_DELPOLICY, syscall.NLM_F_ACK) + return pkgHandle.XfrmPolicyDel(policy) +} - msg := &nl.XfrmUserpolicyId{} - selFromPolicy(&msg.Sel, policy) - msg.Index = uint32(policy.Index) - msg.Dir = uint8(policy.Dir) - req.AddData(msg) - - _, err := req.Execute(syscall.NETLINK_XFRM, 0) +// XfrmPolicyDel will delete an xfrm policy from the system. Note that +// the Tmpls are ignored when matching the policy to delete. +// Equivalent to: `ip xfrm policy del $policy` +func (h *Handle) XfrmPolicyDel(policy *XfrmPolicy) error { + _, err := h.xfrmPolicyGetOrDelete(policy, nl.XFRM_MSG_DELPOLICY) return err } @@ -74,7 +109,14 @@ func XfrmPolicyDel(policy *XfrmPolicy) error { // Equivalent to: `ip xfrm policy show`. // The list can be filtered by ip family. func XfrmPolicyList(family int) ([]XfrmPolicy, error) { - req := nl.NewNetlinkRequest(nl.XFRM_MSG_GETPOLICY, syscall.NLM_F_DUMP) + return pkgHandle.XfrmPolicyList(family) +} + +// XfrmPolicyList gets a list of xfrm policies in the system. +// Equivalent to: `ip xfrm policy show`. +// The list can be filtered by ip family. +func (h *Handle) XfrmPolicyList(family int) ([]XfrmPolicy, error) { + req := h.newNetlinkRequest(nl.XFRM_MSG_GETPOLICY, syscall.NLM_F_DUMP) msg := nl.NewIfInfomsg(family) req.AddData(msg) @@ -86,42 +128,124 @@ func XfrmPolicyList(family int) ([]XfrmPolicy, error) { var res []XfrmPolicy for _, m := range msgs { - msg := nl.DeserializeXfrmUserpolicyInfo(m) - - if family != FAMILY_ALL && family != int(msg.Sel.Family) { + if policy, err := parseXfrmPolicy(m, family); err == nil { + res = append(res, *policy) + } else if err == familyError { continue - } - - var policy XfrmPolicy - - policy.Dst = msg.Sel.Daddr.ToIPNet(msg.Sel.PrefixlenD) - policy.Src = msg.Sel.Saddr.ToIPNet(msg.Sel.PrefixlenS) - policy.Priority = int(msg.Priority) - policy.Index = int(msg.Index) - policy.Dir = Dir(msg.Dir) - - attrs, err := nl.ParseRouteAttr(m[msg.Len():]) - if err != nil { + } else { return nil, err } - - for _, attr := range attrs { - switch attr.Attr.Type { - case nl.XFRMA_TMPL: - max := len(attr.Value) - for i := 0; i < max; i += nl.SizeofXfrmUserTmpl { - var resTmpl XfrmPolicyTmpl - tmpl := nl.DeserializeXfrmUserTmpl(attr.Value[i : i+nl.SizeofXfrmUserTmpl]) - resTmpl.Dst = tmpl.XfrmId.Daddr.ToIP() - resTmpl.Src = tmpl.Saddr.ToIP() - resTmpl.Proto = Proto(tmpl.XfrmId.Proto) - resTmpl.Mode = Mode(tmpl.Mode) - resTmpl.Reqid = int(tmpl.Reqid) - policy.Tmpls = append(policy.Tmpls, resTmpl) - } - } - } - res = append(res, policy) } return res, nil } + +// XfrmPolicyGet gets a the policy described by the index or selector, if found. +// Equivalent to: `ip xfrm policy get { SELECTOR | index INDEX } dir DIR [ctx CTX ] [ mark MARK [ mask MASK ] ] [ ptype PTYPE ]`. +func XfrmPolicyGet(policy *XfrmPolicy) (*XfrmPolicy, error) { + return pkgHandle.XfrmPolicyGet(policy) +} + +// XfrmPolicyGet gets a the policy described by the index or selector, if found. +// Equivalent to: `ip xfrm policy get { SELECTOR | index INDEX } dir DIR [ctx CTX ] [ mark MARK [ mask MASK ] ] [ ptype PTYPE ]`. +func (h *Handle) XfrmPolicyGet(policy *XfrmPolicy) (*XfrmPolicy, error) { + return h.xfrmPolicyGetOrDelete(policy, nl.XFRM_MSG_GETPOLICY) +} + +// XfrmPolicyFlush will flush the policies on the system. +// Equivalent to: `ip xfrm policy flush` +func XfrmPolicyFlush() error { + return pkgHandle.XfrmPolicyFlush() +} + +// XfrmPolicyFlush will flush the policies on the system. +// Equivalent to: `ip xfrm policy flush` +func (h *Handle) XfrmPolicyFlush() error { + req := h.newNetlinkRequest(nl.XFRM_MSG_FLUSHPOLICY, syscall.NLM_F_ACK) + _, err := req.Execute(syscall.NETLINK_XFRM, 0) + return err +} + +func (h *Handle) xfrmPolicyGetOrDelete(policy *XfrmPolicy, nlProto int) (*XfrmPolicy, error) { + req := h.newNetlinkRequest(nlProto, syscall.NLM_F_ACK) + + msg := &nl.XfrmUserpolicyId{} + selFromPolicy(&msg.Sel, policy) + msg.Index = uint32(policy.Index) + msg.Dir = uint8(policy.Dir) + req.AddData(msg) + + if policy.Mark != nil { + out := nl.NewRtAttr(nl.XFRMA_MARK, writeMark(policy.Mark)) + req.AddData(out) + } + + resType := nl.XFRM_MSG_NEWPOLICY + if nlProto == nl.XFRM_MSG_DELPOLICY { + resType = 0 + } + + msgs, err := req.Execute(syscall.NETLINK_XFRM, uint16(resType)) + if err != nil { + return nil, err + } + + if nlProto == nl.XFRM_MSG_DELPOLICY { + return nil, err + } + + p, err := parseXfrmPolicy(msgs[0], FAMILY_ALL) + if err != nil { + return nil, err + } + + return p, nil +} + +func parseXfrmPolicy(m []byte, family int) (*XfrmPolicy, error) { + msg := nl.DeserializeXfrmUserpolicyInfo(m) + + // This is mainly for the policy dump + if family != FAMILY_ALL && family != int(msg.Sel.Family) { + return nil, familyError + } + + var policy XfrmPolicy + + policy.Dst = msg.Sel.Daddr.ToIPNet(msg.Sel.PrefixlenD) + policy.Src = msg.Sel.Saddr.ToIPNet(msg.Sel.PrefixlenS) + policy.Proto = Proto(msg.Sel.Proto) + policy.DstPort = int(nl.Swap16(msg.Sel.Dport)) + policy.SrcPort = int(nl.Swap16(msg.Sel.Sport)) + policy.Priority = int(msg.Priority) + policy.Index = int(msg.Index) + policy.Dir = Dir(msg.Dir) + + attrs, err := nl.ParseRouteAttr(m[msg.Len():]) + if err != nil { + return nil, err + } + + for _, attr := range attrs { + switch attr.Attr.Type { + case nl.XFRMA_TMPL: + max := len(attr.Value) + for i := 0; i < max; i += nl.SizeofXfrmUserTmpl { + var resTmpl XfrmPolicyTmpl + tmpl := nl.DeserializeXfrmUserTmpl(attr.Value[i : i+nl.SizeofXfrmUserTmpl]) + resTmpl.Dst = tmpl.XfrmId.Daddr.ToIP() + resTmpl.Src = tmpl.Saddr.ToIP() + resTmpl.Proto = Proto(tmpl.XfrmId.Proto) + resTmpl.Mode = Mode(tmpl.Mode) + resTmpl.Reqid = int(tmpl.Reqid) + policy.Tmpls = append(policy.Tmpls, resTmpl) + } + case nl.XFRMA_MARK: + mark := nl.DeserializeXfrmMark(attr.Value[:]) + policy.Mark = new(XfrmMark) + policy.Mark.Value = mark.Value + policy.Mark.Mask = mark.Mask + } + } + + return &policy, nil +} diff --git a/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm_state.go b/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm_state.go index 5b8f2df708..662de8d8e0 100644 --- a/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm_state.go +++ b/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm_state.go @@ -1,6 +1,7 @@ package netlink import ( + "fmt" "net" ) @@ -11,7 +12,11 @@ type XfrmStateAlgo struct { TruncateLen int // Auth only } -// EncapType is an enum representing an ipsec template direction. +func (a XfrmStateAlgo) String() string { + return fmt.Sprintf("{Name: %s, Key: 0x%x, TruncateLen: %d}", a.Name, a.Key, a.TruncateLen) +} + +// EncapType is an enum representing the optional packet encapsulation. type EncapType uint8 const ( @@ -22,14 +27,14 @@ const ( func (e EncapType) String() string { switch e { case XFRM_ENCAP_ESPINUDP_NONIKE: - return "espinudp-nonike" + return "espinudp-non-ike" case XFRM_ENCAP_ESPINUDP: return "espinudp" } return "unknown" } -// XfrmEncap represents the encapsulation to use for the ipsec encryption. +// XfrmStateEncap represents the encapsulation to use for the ipsec encryption. type XfrmStateEncap struct { Type EncapType SrcPort int @@ -37,6 +42,11 @@ type XfrmStateEncap struct { OriginalAddress net.IP } +func (e XfrmStateEncap) String() string { + return fmt.Sprintf("{Type: %s, Srcport: %d, DstPort: %d, OriginalAddress: %v}", + e.Type, e.SrcPort, e.DstPort, e.OriginalAddress) +} + // XfrmState represents the state of an ipsec policy. It optionally // contains an XfrmStateAlgo for encryption and one for authentication. type XfrmState struct { @@ -47,7 +57,13 @@ type XfrmState struct { Spi int Reqid int ReplayWindow int + Mark *XfrmMark Auth *XfrmStateAlgo Crypt *XfrmStateAlgo Encap *XfrmStateEncap } + +func (sa XfrmState) String() string { + return fmt.Sprintf("Dst: %v, Src: %v, Proto: %s, Mode: %s, SPI: 0x%x, ReqID: 0x%x, ReplayWindow: %d, Mark: %v, Auth: %v, Crypt: %v, Encap: %v", + sa.Dst, sa.Src, sa.Proto, sa.Mode, sa.Spi, sa.Reqid, sa.ReplayWindow, sa.Mark, sa.Auth, sa.Crypt, sa.Encap) +} diff --git a/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm_state_linux.go b/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm_state_linux.go index fc8604b9d1..f4d6562059 100644 --- a/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm_state_linux.go +++ b/libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm_state_linux.go @@ -34,14 +34,47 @@ func writeStateAlgoAuth(a *XfrmStateAlgo) []byte { return algo.Serialize() } +func writeMark(m *XfrmMark) []byte { + mark := &nl.XfrmMark{ + Value: m.Value, + Mask: m.Mask, + } + if mark.Mask == 0 { + mark.Mask = ^uint32(0) + } + return mark.Serialize() +} + // XfrmStateAdd will add an xfrm state to the system. // Equivalent to: `ip xfrm state add $state` func XfrmStateAdd(state *XfrmState) error { + return pkgHandle.XfrmStateAdd(state) +} + +// XfrmStateAdd will add an xfrm state to the system. +// Equivalent to: `ip xfrm state add $state` +func (h *Handle) XfrmStateAdd(state *XfrmState) error { + return h.xfrmStateAddOrUpdate(state, nl.XFRM_MSG_NEWSA) +} + +// XfrmStateUpdate will update an xfrm state to the system. +// Equivalent to: `ip xfrm state update $state` +func XfrmStateUpdate(state *XfrmState) error { + return pkgHandle.XfrmStateUpdate(state) +} + +// XfrmStateUpdate will update an xfrm state to the system. +// Equivalent to: `ip xfrm state update $state` +func (h *Handle) XfrmStateUpdate(state *XfrmState) error { + return h.xfrmStateAddOrUpdate(state, nl.XFRM_MSG_UPDSA) +} + +func (h *Handle) xfrmStateAddOrUpdate(state *XfrmState, nlProto int) error { // A state with spi 0 can't be deleted so don't allow it to be set if state.Spi == 0 { return fmt.Errorf("Spi must be set when adding xfrm state.") } - req := nl.NewNetlinkRequest(nl.XFRM_MSG_NEWSA, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK) + req := h.newNetlinkRequest(nlProto, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK) msg := &nl.XfrmUsersaInfo{} msg.Family = uint16(nl.GetIPFamily(state.Dst)) @@ -76,6 +109,10 @@ func XfrmStateAdd(state *XfrmState) error { out := nl.NewRtAttr(nl.XFRMA_ENCAP, encapData) req.AddData(out) } + if state.Mark != nil { + out := nl.NewRtAttr(nl.XFRMA_MARK, writeMark(state.Mark)) + req.AddData(out) + } _, err := req.Execute(syscall.NETLINK_XFRM, 0) return err @@ -85,30 +122,29 @@ func XfrmStateAdd(state *XfrmState) error { // the Algos are ignored when matching the state to delete. // Equivalent to: `ip xfrm state del $state` func XfrmStateDel(state *XfrmState) error { - req := nl.NewNetlinkRequest(nl.XFRM_MSG_DELSA, syscall.NLM_F_ACK) + return pkgHandle.XfrmStateDel(state) +} - msg := &nl.XfrmUsersaId{} - msg.Daddr.FromIP(state.Dst) - msg.Family = uint16(nl.GetIPFamily(state.Dst)) - msg.Proto = uint8(state.Proto) - msg.Spi = nl.Swap32(uint32(state.Spi)) - req.AddData(msg) - - saddr := nl.XfrmAddress{} - saddr.FromIP(state.Src) - srcdata := nl.NewRtAttr(nl.XFRMA_SRCADDR, saddr.Serialize()) - - req.AddData(srcdata) - - _, err := req.Execute(syscall.NETLINK_XFRM, 0) +// XfrmStateDel will delete an xfrm state from the system. Note that +// the Algos are ignored when matching the state to delete. +// Equivalent to: `ip xfrm state del $state` +func (h *Handle) XfrmStateDel(state *XfrmState) error { + _, err := h.xfrmStateGetOrDelete(state, nl.XFRM_MSG_DELSA) return err } +// XfrmStateList gets a list of xfrm states in the system. +// Equivalent to: `ip [-4|-6] xfrm state show`. +// The list can be filtered by ip family. +func XfrmStateList(family int) ([]XfrmState, error) { + return pkgHandle.XfrmStateList(family) +} + // XfrmStateList gets a list of xfrm states in the system. // Equivalent to: `ip xfrm state show`. // The list can be filtered by ip family. -func XfrmStateList(family int) ([]XfrmState, error) { - req := nl.NewNetlinkRequest(nl.XFRM_MSG_GETSA, syscall.NLM_F_DUMP) +func (h *Handle) XfrmStateList(family int) ([]XfrmState, error) { + req := h.newNetlinkRequest(nl.XFRM_MSG_GETSA, syscall.NLM_F_DUMP) msgs, err := req.Execute(syscall.NETLINK_XFRM, nl.XFRM_MSG_NEWSA) if err != nil { @@ -117,62 +153,162 @@ func XfrmStateList(family int) ([]XfrmState, error) { var res []XfrmState for _, m := range msgs { - msg := nl.DeserializeXfrmUsersaInfo(m) - - if family != FAMILY_ALL && family != int(msg.Family) { + if state, err := parseXfrmState(m, family); err == nil { + res = append(res, *state) + } else if err == familyError { continue - } - - var state XfrmState - - state.Dst = msg.Id.Daddr.ToIP() - state.Src = msg.Saddr.ToIP() - state.Proto = Proto(msg.Id.Proto) - state.Mode = Mode(msg.Mode) - state.Spi = int(nl.Swap32(msg.Id.Spi)) - state.Reqid = int(msg.Reqid) - state.ReplayWindow = int(msg.ReplayWindow) - - attrs, err := nl.ParseRouteAttr(m[msg.Len():]) - if err != nil { + } else { return nil, err } - - for _, attr := range attrs { - switch attr.Attr.Type { - case nl.XFRMA_ALG_AUTH, nl.XFRMA_ALG_CRYPT: - var resAlgo *XfrmStateAlgo - if attr.Attr.Type == nl.XFRMA_ALG_AUTH { - if state.Auth == nil { - state.Auth = new(XfrmStateAlgo) - } - resAlgo = state.Auth - } else { - state.Crypt = new(XfrmStateAlgo) - resAlgo = state.Crypt - } - algo := nl.DeserializeXfrmAlgo(attr.Value[:]) - (*resAlgo).Name = nl.BytesToString(algo.AlgName[:]) - (*resAlgo).Key = algo.AlgKey - case nl.XFRMA_ALG_AUTH_TRUNC: - if state.Auth == nil { - state.Auth = new(XfrmStateAlgo) - } - algo := nl.DeserializeXfrmAlgoAuth(attr.Value[:]) - state.Auth.Name = nl.BytesToString(algo.AlgName[:]) - state.Auth.Key = algo.AlgKey - state.Auth.TruncateLen = int(algo.AlgTruncLen) - case nl.XFRMA_ENCAP: - encap := nl.DeserializeXfrmEncapTmpl(attr.Value[:]) - state.Encap = new(XfrmStateEncap) - state.Encap.Type = EncapType(encap.EncapType) - state.Encap.SrcPort = int(nl.Swap16(encap.EncapSport)) - state.Encap.DstPort = int(nl.Swap16(encap.EncapDport)) - state.Encap.OriginalAddress = encap.EncapOa.ToIP() - } - - } - res = append(res, state) } return res, nil } + +// XfrmStateGet gets the xfrm state described by the ID, if found. +// Equivalent to: `ip xfrm state get ID [ mark MARK [ mask MASK ] ]`. +// Only the fields which constitue the SA ID must be filled in: +// ID := [ src ADDR ] [ dst ADDR ] [ proto XFRM-PROTO ] [ spi SPI ] +// mark is optional +func XfrmStateGet(state *XfrmState) (*XfrmState, error) { + return pkgHandle.XfrmStateGet(state) +} + +// XfrmStateGet gets the xfrm state described by the ID, if found. +// Equivalent to: `ip xfrm state get ID [ mark MARK [ mask MASK ] ]`. +// Only the fields which constitue the SA ID must be filled in: +// ID := [ src ADDR ] [ dst ADDR ] [ proto XFRM-PROTO ] [ spi SPI ] +// mark is optional +func (h *Handle) XfrmStateGet(state *XfrmState) (*XfrmState, error) { + return h.xfrmStateGetOrDelete(state, nl.XFRM_MSG_GETSA) +} + +func (h *Handle) xfrmStateGetOrDelete(state *XfrmState, nlProto int) (*XfrmState, error) { + req := h.newNetlinkRequest(nlProto, syscall.NLM_F_ACK) + + msg := &nl.XfrmUsersaId{} + msg.Family = uint16(nl.GetIPFamily(state.Dst)) + msg.Daddr.FromIP(state.Dst) + msg.Proto = uint8(state.Proto) + msg.Spi = nl.Swap32(uint32(state.Spi)) + req.AddData(msg) + + if state.Mark != nil { + out := nl.NewRtAttr(nl.XFRMA_MARK, writeMark(state.Mark)) + req.AddData(out) + } + if state.Src != nil { + out := nl.NewRtAttr(nl.XFRMA_SRCADDR, state.Src) + req.AddData(out) + } + + resType := nl.XFRM_MSG_NEWSA + if nlProto == nl.XFRM_MSG_DELSA { + resType = 0 + } + + msgs, err := req.Execute(syscall.NETLINK_XFRM, uint16(resType)) + if err != nil { + return nil, err + } + + if nlProto == nl.XFRM_MSG_DELSA { + return nil, nil + } + + s, err := parseXfrmState(msgs[0], FAMILY_ALL) + if err != nil { + return nil, err + } + + return s, nil +} + +var familyError = fmt.Errorf("family error") + +func parseXfrmState(m []byte, family int) (*XfrmState, error) { + msg := nl.DeserializeXfrmUsersaInfo(m) + + // This is mainly for the state dump + if family != FAMILY_ALL && family != int(msg.Family) { + return nil, familyError + } + + var state XfrmState + + state.Dst = msg.Id.Daddr.ToIP() + state.Src = msg.Saddr.ToIP() + state.Proto = Proto(msg.Id.Proto) + state.Mode = Mode(msg.Mode) + state.Spi = int(nl.Swap32(msg.Id.Spi)) + state.Reqid = int(msg.Reqid) + state.ReplayWindow = int(msg.ReplayWindow) + + attrs, err := nl.ParseRouteAttr(m[nl.SizeofXfrmUsersaInfo:]) + if err != nil { + return nil, err + } + + for _, attr := range attrs { + switch attr.Attr.Type { + case nl.XFRMA_ALG_AUTH, nl.XFRMA_ALG_CRYPT: + var resAlgo *XfrmStateAlgo + if attr.Attr.Type == nl.XFRMA_ALG_AUTH { + if state.Auth == nil { + state.Auth = new(XfrmStateAlgo) + } + resAlgo = state.Auth + } else { + state.Crypt = new(XfrmStateAlgo) + resAlgo = state.Crypt + } + algo := nl.DeserializeXfrmAlgo(attr.Value[:]) + (*resAlgo).Name = nl.BytesToString(algo.AlgName[:]) + (*resAlgo).Key = algo.AlgKey + case nl.XFRMA_ALG_AUTH_TRUNC: + if state.Auth == nil { + state.Auth = new(XfrmStateAlgo) + } + algo := nl.DeserializeXfrmAlgoAuth(attr.Value[:]) + state.Auth.Name = nl.BytesToString(algo.AlgName[:]) + state.Auth.Key = algo.AlgKey + state.Auth.TruncateLen = int(algo.AlgTruncLen) + case nl.XFRMA_ENCAP: + encap := nl.DeserializeXfrmEncapTmpl(attr.Value[:]) + state.Encap = new(XfrmStateEncap) + state.Encap.Type = EncapType(encap.EncapType) + state.Encap.SrcPort = int(nl.Swap16(encap.EncapSport)) + state.Encap.DstPort = int(nl.Swap16(encap.EncapDport)) + state.Encap.OriginalAddress = encap.EncapOa.ToIP() + case nl.XFRMA_MARK: + mark := nl.DeserializeXfrmMark(attr.Value[:]) + state.Mark = new(XfrmMark) + state.Mark.Value = mark.Value + state.Mark.Mask = mark.Mask + } + } + + return &state, nil +} + +// XfrmStateFlush will flush the xfrm state on the system. +// proto = 0 means any transformation protocols +// Equivalent to: `ip xfrm state flush [ proto XFRM-PROTO ]` +func XfrmStateFlush(proto Proto) error { + return pkgHandle.XfrmStateFlush(proto) +} + +// XfrmStateFlush will flush the xfrm state on the system. +// proto = 0 means any transformation protocols +// Equivalent to: `ip xfrm state flush [ proto XFRM-PROTO ]` +func (h *Handle) XfrmStateFlush(proto Proto) error { + req := h.newNetlinkRequest(nl.XFRM_MSG_FLUSHSA, syscall.NLM_F_ACK) + + req.AddData(&nl.XfrmUsersaFlush{Proto: uint8(proto)}) + + _, err := req.Execute(syscall.NETLINK_XFRM, 0) + if err != nil { + return err + } + + return nil +} diff --git a/libnetwork/drivers/overlay/ov_utils.go b/libnetwork/drivers/overlay/ov_utils.go index 42c44b9675..bcaea768c5 100644 --- a/libnetwork/drivers/overlay/ov_utils.go +++ b/libnetwork/drivers/overlay/ov_utils.go @@ -6,7 +6,6 @@ import ( "github.com/docker/libnetwork/netutils" "github.com/docker/libnetwork/osl" "github.com/vishvananda/netlink" - "github.com/vishvananda/netlink/nl" ) func validateID(nid, eid string) error { @@ -54,7 +53,7 @@ func createVxlan(name string, vni uint32) error { LinkAttrs: netlink.LinkAttrs{Name: name}, VxlanId: int(vni), Learning: true, - Port: int(nl.Swap16(vxlanPort)), //network endian order + Port: vxlanPort, Proxy: true, L3miss: true, L2miss: true,