コード例 #1
0
ファイル: filter_linux.go プロジェクト: devick/flynn
func DeserializeRtab(b []byte) [256]uint32 {
	var rtab [256]uint32
	native := nl.NativeEndian()
	r := bytes.NewReader(b)
	_ = binary.Read(r, native, &rtab)
	return rtab
}
コード例 #2
0
ファイル: route_linux.go プロジェクト: devick/flynn
// deserializeRoute decodes a binary netlink message into a Route struct
func deserializeRoute(m []byte) (Route, error) {
	route := Route{}
	msg := nl.DeserializeRtMsg(m)
	attrs, err := nl.ParseRouteAttr(m[msg.Len():])
	if err != nil {
		return route, err
	}
	route.Scope = Scope(msg.Scope)
	route.Flags = int(msg.Flags)

	native := nl.NativeEndian()
	for _, attr := range attrs {
		switch attr.Attr.Type {
		case syscall.RTA_GATEWAY:
			route.Gw = net.IP(attr.Value)
		case syscall.RTA_PREFSRC:
			route.Src = net.IP(attr.Value)
		case syscall.RTA_DST:
			route.Dst = &net.IPNet{
				IP:   attr.Value,
				Mask: net.CIDRMask(int(msg.Dst_len), 8*len(attr.Value)),
			}
		case syscall.RTA_OIF:
			routeIndex := int(native.Uint32(attr.Value[0:4]))
			route.LinkIndex = routeIndex
		}
	}
	return route, nil
}
コード例 #3
0
ファイル: filter_linux.go プロジェクト: devick/flynn
func parseFwData(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error) {
	native = nl.NativeEndian()
	fw := filter.(*Fw)
	detailed := true
	for _, datum := range data {
		switch datum.Attr.Type {
		case nl.TCA_FW_MASK:
			fw.Mask = native.Uint32(datum.Value[0:4])
		case nl.TCA_FW_CLASSID:
			fw.ClassId = native.Uint32(datum.Value[0:4])
		case nl.TCA_FW_INDEV:
			fw.InDev = string(datum.Value[:len(datum.Value)-1])
		case nl.TCA_FW_POLICE:
			adata, _ := nl.ParseRouteAttr(datum.Value)
			for _, aattr := range adata {
				switch aattr.Attr.Type {
				case nl.TCA_POLICE_TBF:
					fw.Police = *nl.DeserializeTcPolice(aattr.Value)
				case nl.TCA_POLICE_RATE:
					fw.Rtab = DeserializeRtab(aattr.Value)
				case nl.TCA_POLICE_PEAKRATE:
					fw.Ptab = DeserializeRtab(aattr.Value)
				}
			}
		}
	}
	return detailed, nil
}
コード例 #4
0
ファイル: filter_linux.go プロジェクト: devick/flynn
func parseU32Data(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error) {
	native = nl.NativeEndian()
	u32 := filter.(*U32)
	detailed := false
	for _, datum := range data {
		switch datum.Attr.Type {
		case nl.TCA_U32_SEL:
			detailed = true
			sel := nl.DeserializeTcU32Sel(datum.Value)
			// only parse if we have a very basic redirect
			if sel.Flags&nl.TC_U32_TERMINAL == 0 || sel.Nkeys != 1 {
				return detailed, nil
			}
		case nl.TCA_U32_ACT:
			table, 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")
			}
			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)
						}
					}
				}
			}
		}
	}
	return detailed, nil
}
コード例 #5
0
ファイル: qdisc_linux.go プロジェクト: devick/flynn
func parseTbfData(qdisc Qdisc, data []syscall.NetlinkRouteAttr) error {
	native = nl.NativeEndian()
	tbf := qdisc.(*Tbf)
	for _, datum := range data {
		switch datum.Attr.Type {
		case nl.TCA_TBF_PARMS:
			opt := nl.DeserializeTcTbfQopt(datum.Value)
			tbf.Rate = uint64(opt.Rate.Rate)
			tbf.Limit = opt.Limit
			tbf.Buffer = opt.Buffer
		case nl.TCA_TBF_RATE64:
			tbf.Rate = native.Uint64(datum.Value[0:4])
		}
	}
	return nil
}
コード例 #6
0
ファイル: qdisc_linux.go プロジェクト: devick/flynn
func parseHtbData(qdisc Qdisc, data []syscall.NetlinkRouteAttr) error {
	native = nl.NativeEndian()
	htb := qdisc.(*Htb)
	for _, datum := range data {
		switch datum.Attr.Type {
		case nl.TCA_HTB_INIT:
			opt := nl.DeserializeTcHtbGlob(datum.Value)
			htb.Version = opt.Version
			htb.Rate2Quantum = opt.Rate2Quantum
			htb.Defcls = opt.Defcls
			htb.Debug = opt.Debug
			htb.DirectPkts = opt.DirectPkts
		case nl.TCA_HTB_DIRECT_QLEN:
			// TODO
			//htb.DirectQlen = native.uint32(datum.Value)
		}
	}
	return nil
}
コード例 #7
0
ファイル: route_linux.go プロジェクト: devick/flynn
func 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")
	}

	msg.Scope = uint8(route.Scope)
	msg.Flags = uint32(route.Flags)
	family := -1
	var rtAttrs []*nl.RtAttr

	if route.Dst != nil && route.Dst.IP != nil {
		dstLen, _ := route.Dst.Mask.Size()
		msg.Dst_len = uint8(dstLen)
		dstFamily := nl.GetIPFamily(route.Dst.IP)
		family = dstFamily
		var dstData []byte
		if dstFamily == FAMILY_V4 {
			dstData = route.Dst.IP.To4()
		} else {
			dstData = route.Dst.IP.To16()
		}
		rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_DST, dstData))
	}

	if route.Src != nil {
		srcFamily := nl.GetIPFamily(route.Src)
		if family != -1 && family != srcFamily {
			return fmt.Errorf("source and destination ip are not the same IP family")
		}
		family = srcFamily
		var srcData []byte
		if srcFamily == FAMILY_V4 {
			srcData = route.Src.To4()
		} else {
			srcData = route.Src.To16()
		}
		// The commonly used src ip for routes is actually PREFSRC
		rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_PREFSRC, srcData))
	}

	if route.Gw != nil {
		gwFamily := nl.GetIPFamily(route.Gw)
		if family != -1 && family != gwFamily {
			return fmt.Errorf("gateway, source, and destination ip are not the same IP family")
		}
		family = gwFamily
		var gwData []byte
		if gwFamily == FAMILY_V4 {
			gwData = route.Gw.To4()
		} else {
			gwData = route.Gw.To16()
		}
		rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_GATEWAY, gwData))
	}

	msg.Family = uint8(family)

	req.AddData(msg)
	for _, attr := range rtAttrs {
		req.AddData(attr)
	}

	var (
		b      = make([]byte, 4)
		native = nl.NativeEndian()
	)
	native.PutUint32(b, uint32(route.LinkIndex))

	req.AddData(nl.NewRtAttr(syscall.RTA_OIF, b))

	_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
	return err
}
コード例 #8
0
ファイル: filter_linux.go プロジェクト: devick/flynn
func SerializeRtab(rtab [256]uint32) []byte {
	native := nl.NativeEndian()
	var w bytes.Buffer
	_ = binary.Write(&w, native, rtab)
	return w.Bytes()
}
コード例 #9
0
ファイル: filter_linux.go プロジェクト: devick/flynn
// FilterAdd will add a filter to the system.
// Equivalent to: `tc filter add $filter`
func 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)
	base := filter.Attrs()
	msg := &nl.TcMsg{
		Family:  nl.FAMILY_ALL,
		Ifindex: int32(base.LinkIndex),
		Handle:  base.Handle,
		Parent:  base.Parent,
		Info:    MakeHandle(base.Priority, nl.Swap16(base.Protocol)),
	}
	req.AddData(msg)
	req.AddData(nl.NewRtAttr(nl.TCA_KIND, nl.ZeroTerminated(filter.Type())))

	options := nl.NewRtAttr(nl.TCA_OPTIONS, nil)
	if u32, ok := filter.(*U32); ok {
		// match all
		sel := nl.TcU32Sel{
			Nkeys: 1,
			Flags: nl.TC_U32_TERMINAL,
		}
		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),
		}
		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)
			native.PutUint32(b, fw.Mask)
			nl.NewRtAttrChild(options, nl.TCA_FW_MASK, b)
		}
		if fw.InDev != "" {
			nl.NewRtAttrChild(options, nl.TCA_FW_INDEV, nl.ZeroTerminated(fw.InDev))
		}
		if (fw.Police != nl.TcPolice{}) {

			police := nl.NewRtAttrChild(options, nl.TCA_FW_POLICE, nil)
			nl.NewRtAttrChild(police, nl.TCA_POLICE_TBF, fw.Police.Serialize())
			if (fw.Police.Rate != nl.TcRateSpec{}) {
				payload := SerializeRtab(fw.Rtab)
				nl.NewRtAttrChild(police, nl.TCA_POLICE_RATE, payload)
			}
			if (fw.Police.PeakRate != nl.TcRateSpec{}) {
				payload := SerializeRtab(fw.Ptab)
				nl.NewRtAttrChild(police, nl.TCA_POLICE_PEAKRATE, payload)
			}
		}
		if fw.ClassId != 0 {
			b := make([]byte, 4)
			native.PutUint32(b, fw.ClassId)
			nl.NewRtAttrChild(options, nl.TCA_FW_CLASSID, b)
		}
	}

	req.AddData(options)
	_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
	return err
}
コード例 #10
0
ファイル: link_linux.go プロジェクト: devick/flynn
package netlink

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"net"
	"os"
	"syscall"
	"unsafe"

	"github.com/flynn/flynn/Godeps/_workspace/src/github.com/vishvananda/netlink/nl"
)

var native = nl.NativeEndian()
var lookupByDump = false

var macvlanModes = [...]uint32{
	0,
	nl.MACVLAN_MODE_PRIVATE,
	nl.MACVLAN_MODE_VEPA,
	nl.MACVLAN_MODE_BRIDGE,
	nl.MACVLAN_MODE_PASSTHRU,
	nl.MACVLAN_MODE_SOURCE,
}

func ensureIndex(link *LinkAttrs) {
	if link != nil && link.Index == 0 {
		newlink, _ := LinkByName(link.Name)
		if newlink != nil {
			link.Index = newlink.Attrs().Index