diff --git a/GITIGNORE b/.gitignore similarity index 95% rename from GITIGNORE rename to .gitignore index 2c10515..4bef869 100644 --- a/GITIGNORE +++ b/.gitignore @@ -6,3 +6,4 @@ tools/get_routes tools/get_addrs tools/get_links tools/ifmanip +pkg diff --git a/src/attr_helpers.go b/src/attr_helpers.go deleted file mode 100644 index fe99936..0000000 --- a/src/attr_helpers.go +++ /dev/null @@ -1,79 +0,0 @@ -package netlink - -/* - Copyright (c) 2011, Abneptis LLC. All rights reserved. - Original Author: James D. Nurmi - - See LICENSE for details -*/ - -import "log" - -import "encoding/binary" -import "os" -import "bytes" - -// The attributeFinder interface should be used by READERS, -// Writers will need to use an AttributeWriter -type AttributeFinder interface { - GetAttribute(AttributeType)(Attribute, os.Error) -} - -// AttributeWriters allow attributes to be added/updated. -type AttributeWriter interface { - SetAttribute(Attribute) -} - -// Sets the attribute value to the string specified by 's'. -// s will be NULL terminated. -func SetAttributeCString(aw AttributeWriter, at AttributeType, s string){ - buff := bytes.NewBufferString(s+ "\x00") - log.Printf("Buff: %X", buff.Bytes()) - aw.SetAttribute(Attribute{Type: at, Body: buff.Bytes() }) - return -} - -// Returns the attribute as an uint32 (or an error if the attr size is not -// 32 bits. -func GetAttributeUint32(af AttributeFinder, at AttributeType)(out uint32, err os.Error){ - attr, err := af.GetAttribute(at) - if err == nil { - body := attr.Body - if len(body) != 4 { - err = os.NewError("Attribute wrong size for Uint32") - } else { - out = binary.LittleEndian.Uint32(body) - } - } - return -} - -// Gets an attribute value as a string. -// Note, for much of RTNetlink, you want GetAttributeCString, -// which will verify and chop the tailing NULL. -func GetAttributeString(af AttributeFinder, at AttributeType)(out string, err os.Error){ - attr, err := af.GetAttribute(at) - if err == nil { - out = string(attr.Body) - } - return -} - -// Same as GetAttributeString, but expects the string to be NULL terminated, -// the null terminator will be stripped.. -func GetAttributeCString(af AttributeFinder, at AttributeType)(out string, err os.Error){ - attr, err := af.GetAttribute(at) - if err == nil { - outbody := attr.Body - if len(outbody) == 0 { - err = os.NewError("Invalid body") - } else { - if outbody[len(outbody) -1 ] != 0 { - err = os.NewError("Expected NULL-terminated string") - } else { - out = string(outbody[0: len(outbody) - 1]) - } - } - } - return -} diff --git a/src/attribute.go b/src/attribute.go deleted file mode 100644 index e44be9c..0000000 --- a/src/attribute.go +++ /dev/null @@ -1,73 +0,0 @@ -package netlink -/* - Copyright (c) 2011, Abneptis LLC. All rights reserved. - Original Author: James D. Nurmi - - See LICENSE for details -*/ - -import "fmt" -import "os" -import "bytes" -import "encoding/binary" - -// A basic netlink type used for identifying -// nlattrs in a message. -type AttributeType uint16 - -// An attribute is used to hold an Netlink Attribute. -// An attribute is stored as a Length-Type-Value tuple. -// Length and Type are 16 bit integers, so values may not -// exceed 2^16. -type Attribute struct { - Type AttributeType - Body []byte -} - -// Marshals a netlink attribute as a full LTV tuple. -func (self Attribute)MarshalNetlink(pad int)(out []byte, err os.Error){ - l := len(self.Body) - out = make([]byte, l + 4) - binary.LittleEndian.PutUint16(out[0:2], uint16(len(self.Body)+4)) - binary.LittleEndian.PutUint16(out[2:4], uint16(self.Type)) - copy(out[4:], self.Body[0:]) - out = PadBytes(out, pad) - return -} - -// Unmarshals a netlink attribute. -func UnmarshalAttributes(in []byte, padding int)(out []Attribute, err os.Error){ - pos := 0 - for pos < len(in) { - l := binary.LittleEndian.Uint16(in[pos:pos+2]) - if int(l) > len(in) - pos { - err = os.NewError("Can't parse attribute (too long)") - break - } - if l > 4 { - t := binary.LittleEndian.Uint16(in[pos+2:pos+4]) - out = append(out, Attribute{Type: AttributeType(t), Body:in[pos+4:pos + int(l)]}) - pos = Reposition(pos + int(l), padding) - } else { - err = os.NewError(fmt.Sprintf("Invalid Attributeibute (Len: %d):", l)) - break - } - } - return -} - -// Returns the padded bytes of a marshalled list of attributes. -// Any marshalling error will cause the sequence to abort. -func MarshalAttributes(in []Attribute, padding int)(out []byte, err os.Error){ - for i := range(in){ - var b []byte - b, err = in[i].MarshalNetlink(padding) - if err == nil { - out = bytes.Join([][]byte{out, b}, []byte{}) - } else { - break - } - } - return -} - diff --git a/src/error.go b/src/error.go deleted file mode 100644 index 27dff02..0000000 --- a/src/error.go +++ /dev/null @@ -1,43 +0,0 @@ -package netlink -/* - Copyright (c) 2011, Abneptis LLC. All rights reserved. - Original Author: James D. Nurmi - - See LICENSE for details -*/ - -import "fmt" -import "encoding/binary" -import "os" -import "syscall" - -// Unlike other headers, errors MAY be longer than the minimum length. -const ERROR_LENGTH = HEADER_LENGTH+4 -// Represents a netlink Error message. -type Error [ERROR_LENGTH]byte - -// The error code (-errno) of the netlink message. -// 0 is used for netlink ACK's. -func (self Error)Code()(int32){ - return int32(binary.LittleEndian.Uint32(self[0:4])) -} - -// Marshals an error to the wire. -func (self Error)MarshalNetlink(pad int)(out []byte, err os.Error){ - out = PadBytes(self[0:ERROR_LENGTH], pad) - return -} - -// Unmarshals an error from a netlink message. -func (self *Error)UnmarshalNetlink(in []byte, pad int)(err os.Error){ - if len(in) < ERROR_LENGTH { - return os.NewError(fmt.Sprintf("Invalid netlink error length: %d", len(in))) - } - copy(self[0:ERROR_LENGTH], in) - return -} - -// Implements os.Error by using syscall.Errstr(-Code()) -func (self Error)String()(string){ - return syscall.Errstr(int(-self.Code())) -} diff --git a/src/handler.go b/src/handler.go deleted file mode 100644 index a734fb6..0000000 --- a/src/handler.go +++ /dev/null @@ -1,84 +0,0 @@ -package netlink - -/* - Copyright (c) 2011, Abneptis LLC. All rights reserved. - Original Author: James D. Nurmi - - See LICENSE for details -*/ - -//import "log" -import "bufio" -import "os" -import "fmt" -import "sync" - -// A handler implements a simple Mux for netlink messages, ensuring -// each query gets a unique sequence number and a channel to collect responses. -type Handler struct { - sock *Socket - recipients map[uint32]chan Message - next_seq uint32 - lock sync.Mutex -} - -// Used as an atomic counter for sequence numbering. -// No check is made to see that sequences aren't still in use on roll-over. -func (self *Handler)Seq()(out uint32){ - self.lock.Lock() - out = self.next_seq - self.next_seq++ - self.lock.Unlock() - return -} - -func NewHandler(sock *Socket)(*Handler){ - return &Handler{sock:sock, recipients: map[uint32]chan Message{}, next_seq: 1} -} - -// Send a message. If SequenceNumber is unset, Seq() will be used -// to generate one. -func (self *Handler)Query(msg Message, l int, pad int)(ch chan Message, err os.Error){ - if msg.Header.MessageSequence() == 0 { - msg.Header.SetMessageSequence(self.Seq()) - } - ob, err := msg.MarshalNetlink(pad) - if err == nil { - ch = make(chan Message, l) - self.recipients[msg.Header.MessageSequence()] = ch - _, err = self.sock.Write(ob) - } - return -} - -// Usually called in a goroutine, Start spawns a thread -// that demux's incoming netlink responses. -// Echan is used to report internal netlink errors, and may -// be set to nil (but you will likely miss bugs!) -func (self *Handler)Start(echan chan os.Error){ - r := bufio.NewReader(self.sock) - for { - msg, err := ReadMessage(r, 4) - if err == nil { - if self.recipients[msg.Header.MessageSequence()] == nil { - if nil != echan { - echan <- os.NewError(fmt.Sprintf("GoNetlink: No handler found for seq %d", - msg.Header.MessageSequence())) - } - continue - } else { - self.recipients[msg.Header.MessageSequence()] <- *msg - if msg.Header.MessageFlags() & NLM_F_MULTI == 0 { - close(self.recipients[msg.Header.MessageSequence()]) - self.recipients[msg.Header.MessageSequence()] = nil, false - } - } - } else { - if nil != echan { - echan <- err - } - } - } - return -} - diff --git a/src/header.go b/src/header.go deleted file mode 100644 index b22959d..0000000 --- a/src/header.go +++ /dev/null @@ -1,53 +0,0 @@ -package netlink - -/* - Copyright (c) 2011, Abneptis LLC. All rights reserved. - Original Author: James D. Nurmi - - See LICENSE for details -*/ - -import "os" -import "encoding/binary" - -const HEADER_LENGTH = 16 - -// Represents the header of a netlink.Message -type Header [HEADER_LENGTH]byte - -func (self Header)Len()(int){ return HEADER_LENGTH} - -func (self Header)MessageLength()(uint32) { return binary.LittleEndian.Uint32(self[0:4]) } -func (self *Header)SetMessageLength(in uint32) { binary.LittleEndian.PutUint32(self[0:4], in)} -func (self Header)MessageType()(MessageType) { return MessageType(binary.LittleEndian.Uint16(self[4:6]))} -func (self Header)MessageFlags()(MessageFlags) { return MessageFlags(binary.LittleEndian.Uint16(self[6:8]))} -func (self Header)MessageSequence()(uint32) { return binary.LittleEndian.Uint32(self[8:12])} -func (self *Header)SetMessageSequence(in uint32) { binary.LittleEndian.PutUint32(self[8:12], in)} -func (self Header)MessagePid()(uint32) { return binary.LittleEndian.Uint32(self[12:16])} - -func NewHeader(t MessageType, f MessageFlags, seq uint32)(h *Header){ - h = &Header{} - binary.LittleEndian.PutUint32(h[0:4], HEADER_LENGTH) - binary.LittleEndian.PutUint16(h[4:6], uint16(t)) - binary.LittleEndian.PutUint16(h[6:8], uint16(f)) - binary.LittleEndian.PutUint32(h[8:12], seq) - binary.LittleEndian.PutUint32(h[12:16], 0) - - return -} - -func (self Header)MarshalNetlink(pad int)(out []byte, err os.Error){ - out = make([]byte, HEADER_LENGTH) - copy(out, self[0:HEADER_LENGTH]) - out = PadBytes(out, pad) - return -} - -func (self *Header)UnmarshalNetlink(in []byte, pad int)(err os.Error){ - if len(in) != HEADER_LENGTH { - err = os.NewError("Incorrect NetlinkHeader length") - } else { - copy(self[0:HEADER_LENGTH], in[0:HEADER_LENGTH]) - } - return -} diff --git a/src/message.go b/src/message.go deleted file mode 100644 index a1ae095..0000000 --- a/src/message.go +++ /dev/null @@ -1,69 +0,0 @@ -package netlink - -/* - Copyright (c) 2011, Abneptis LLC. All rights reserved. - Original Author: James D. Nurmi - - See LICENSE for details -*/ - -import "fmt" -import "bytes" -import "os" -import "io" - -// A netlink message contains a Netlink header, -// and a body of bytes. -type Message struct { - Header *Header - Body []byte -} - -// NetlinkMarshaler's are used to pad and format netlink data. -type NetlinkMarshaler interface { - MarshalNetlink(int)([]byte, os.Error) -} - -// Creates a new message from a marshalable object -func NewMessage(t MessageType, f MessageFlags, u NetlinkMarshaler, pad int)(msg *Message, err os.Error){ - msg = &Message{Header: NewHeader(t,f,0) } - msg.Body, err = u.MarshalNetlink(pad) - if err == nil { - msg.Header.SetMessageLength(uint32(msg.Header.Len()) + uint32(len (msg.Body))) - } - return -} - -// Reads a message from an io.Reader, with a specified padding. -// NB: Netlink uses a very strict protocol, and it is encouraged -// that r be a bufio.Reader -func ReadMessage(r io.Reader, pad int)(msg *Message, err os.Error){ - var n int - msg = &Message{Header: &Header{}} - ib := make([]byte, msg.Header.Len()) - n, err = r.Read(ib) - if err == nil && n != msg.Header.Len() { - err = os.NewError("Incomplete netlink header") - } - if err == nil { - err = msg.Header.UnmarshalNetlink(ib, pad) - if err == nil { - msg.Body = make([]byte, msg.Header.MessageLength() - uint32(msg.Header.Len())) - n, err = r.Read(msg.Body) - if err == nil && n != int(msg.Header.MessageLength()) - int(msg.Header.Len()) { - err = os.NewError(fmt.Sprintf("Incomplete netlink message body (Got: %d; Expected: %d)", n, int(msg.Header.MessageLength()) - int(msg.Header.Len()))) - } else { - } - } - } - return -} - -// Marshals a message with appropriate padding (generally none). -func (self Message)MarshalNetlink(pad int)(out []byte, err os.Error){ - hdrout, err := self.Header.MarshalNetlink(pad) - if err == nil { - out = bytes.Join([][]byte{hdrout, self.Body}, []byte{}) - } - return -} diff --git a/src/address.go b/src/netlink/address.go similarity index 100% rename from src/address.go rename to src/netlink/address.go diff --git a/src/netlink/attr_helpers.go b/src/netlink/attr_helpers.go new file mode 100644 index 0000000..c21f6a9 --- /dev/null +++ b/src/netlink/attr_helpers.go @@ -0,0 +1,82 @@ +package netlink + +/* + Copyright (c) 2011, Abneptis LLC. All rights reserved. + Original Author: James D. Nurmi + + See LICENSE for details +*/ + +import "log" + +import ( + "encoding/binary" + "errors" +) + +import "bytes" + +// The attributeFinder interface should be used by READERS, +// Writers will need to use an AttributeWriter +type AttributeFinder interface { + GetAttribute(AttributeType) (Attribute, error) +} + +// AttributeWriters allow attributes to be added/updated. +type AttributeWriter interface { + SetAttribute(Attribute) +} + +// Sets the attribute value to the string specified by 's'. +// s will be NULL terminated. +func SetAttributeCString(aw AttributeWriter, at AttributeType, s string) { + buff := bytes.NewBufferString(s + "\x00") + log.Printf("Buff: %X", buff.Bytes()) + aw.SetAttribute(Attribute{Type: at, Body: buff.Bytes()}) + return +} + +// Returns the attribute as an uint32 (or an error if the attr size is not +// 32 bits. +func GetAttributeUint32(af AttributeFinder, at AttributeType) (out uint32, err error) { + attr, err := af.GetAttribute(at) + if err == nil { + body := attr.Body + if len(body) != 4 { + err = errors.New("Attribute wrong size for Uint32") + } else { + out = binary.LittleEndian.Uint32(body) + } + } + return +} + +// Gets an attribute value as a string. +// Note, for much of RTNetlink, you want GetAttributeCString, +// which will verify and chop the tailing NULL. +func GetAttributeString(af AttributeFinder, at AttributeType) (out string, err error) { + attr, err := af.GetAttribute(at) + if err == nil { + out = string(attr.Body) + } + return +} + +// Same as GetAttributeString, but expects the string to be NULL terminated, +// the null terminator will be stripped.. +func GetAttributeCString(af AttributeFinder, at AttributeType) (out string, err error) { + attr, err := af.GetAttribute(at) + if err == nil { + outbody := attr.Body + if len(outbody) == 0 { + err = errors.New("Invalid body") + } else { + if outbody[len(outbody)-1] != 0 { + err = errors.New("Expected NULL-terminated string") + } else { + out = string(outbody[0 : len(outbody)-1]) + } + } + } + return +} diff --git a/src/netlink/attribute.go b/src/netlink/attribute.go new file mode 100644 index 0000000..a9fa3fc --- /dev/null +++ b/src/netlink/attribute.go @@ -0,0 +1,76 @@ +package netlink + +/* + Copyright (c) 2011, Abneptis LLC. All rights reserved. + Original Author: James D. Nurmi + + See LICENSE for details +*/ + +import "fmt" + +import "bytes" +import ( + "encoding/binary" + "errors" +) + +// A basic netlink type used for identifying +// nlattrs in a message. +type AttributeType uint16 + +// An attribute is used to hold an Netlink Attribute. +// An attribute is stored as a Length-Type-Value tuple. +// Length and Type are 16 bit integers, so values may not +// exceed 2^16. +type Attribute struct { + Type AttributeType + Body []byte +} + +// Marshals a netlink attribute as a full LTV tuple. +func (self Attribute) MarshalNetlink(pad int) (out []byte, err error) { + l := len(self.Body) + out = make([]byte, l+4) + binary.LittleEndian.PutUint16(out[0:2], uint16(len(self.Body)+4)) + binary.LittleEndian.PutUint16(out[2:4], uint16(self.Type)) + copy(out[4:], self.Body[0:]) + out = PadBytes(out, pad) + return +} + +// Unmarshals a netlink attribute. +func UnmarshalAttributes(in []byte, padding int) (out []Attribute, err error) { + pos := 0 + for pos < len(in) { + l := binary.LittleEndian.Uint16(in[pos : pos+2]) + if int(l) > len(in)-pos { + err = errors.New("Can't parse attribute (too long)") + break + } + if l > 4 { + t := binary.LittleEndian.Uint16(in[pos+2 : pos+4]) + out = append(out, Attribute{Type: AttributeType(t), Body: in[pos+4 : pos+int(l)]}) + pos = Reposition(pos+int(l), padding) + } else { + err = errors.New(fmt.Sprintf("Invalid Attributeibute (Len: %d):", l)) + break + } + } + return +} + +// Returns the padded bytes of a marshalled list of attributes. +// Any marshalling error will cause the sequence to abort. +func MarshalAttributes(in []Attribute, padding int) (out []byte, err error) { + for i := range in { + var b []byte + b, err = in[i].MarshalNetlink(padding) + if err == nil { + out = bytes.Join([][]byte{out, b}, []byte{}) + } else { + break + } + } + return +} diff --git a/src/netlink/error.go b/src/netlink/error.go new file mode 100644 index 0000000..ed96f4c --- /dev/null +++ b/src/netlink/error.go @@ -0,0 +1,44 @@ +package netlink + +/* + Copyright (c) 2011, Abneptis LLC. All rights reserved. + Original Author: James D. Nurmi + + See LICENSE for details +*/ + +import "fmt" +import ( + "encoding/binary" + "errors" +) + +//import "syscall" + +// Unlike other headers, errors MAY be longer than the minimum length. +const ERROR_LENGTH = HEADER_LENGTH + 4 + +// Represents a netlink Error message. +type Error [ERROR_LENGTH]byte + +// The error code (-errno) of the netlink message. +// 0 is used for netlink ACK's. +func (self Error) Code() int32 { + return int32(binary.LittleEndian.Uint32(self[0:4])) +} + +// Marshals an error to the wire. +func (self Error) MarshalNetlink(pad int) (out []byte, err error) { + out = PadBytes(self[0:ERROR_LENGTH], pad) + return +} + +// Unmarshals an error from a netlink message. +func (self *Error) UnmarshalNetlink(in []byte, pad int) (err error) { + if len(in) < ERROR_LENGTH { + return errors.New(fmt.Sprintf("Invalid netlink error length: %d", len(in))) + } + copy(self[0:ERROR_LENGTH], in) + return +} + diff --git a/src/family.go b/src/netlink/family.go similarity index 100% rename from src/family.go rename to src/netlink/family.go diff --git a/src/flags.go b/src/netlink/flags.go similarity index 100% rename from src/flags.go rename to src/netlink/flags.go diff --git a/src/netlink/handler.go b/src/netlink/handler.go new file mode 100644 index 0000000..d65523b --- /dev/null +++ b/src/netlink/handler.go @@ -0,0 +1,86 @@ +package netlink + +/* + Copyright (c) 2011, Abneptis LLC. All rights reserved. + Original Author: James D. Nurmi + + See LICENSE for details +*/ + +//import "log" +import ( + "bufio" + "errors" +) + +import "fmt" +import "sync" + +// A handler implements a simple Mux for netlink messages, ensuring +// each query gets a unique sequence number and a channel to collect responses. +type Handler struct { + sock *Socket + recipients map[uint32]chan Message + next_seq uint32 + lock sync.Mutex +} + +// Used as an atomic counter for sequence numbering. +// No check is made to see that sequences aren't still in use on roll-over. +func (self *Handler) Seq() (out uint32) { + self.lock.Lock() + out = self.next_seq + self.next_seq++ + self.lock.Unlock() + return +} + +func NewHandler(sock *Socket) *Handler { + return &Handler{sock: sock, recipients: map[uint32]chan Message{}, next_seq: 1} +} + +// Send a message. If SequenceNumber is unset, Seq() will be used +// to generate one. +func (self *Handler) Query(msg Message, l int, pad int) (ch chan Message, err error) { + if msg.Header.MessageSequence() == 0 { + msg.Header.SetMessageSequence(self.Seq()) + } + ob, err := msg.MarshalNetlink(pad) + if err == nil { + ch = make(chan Message, l) + self.recipients[msg.Header.MessageSequence()] = ch + _, err = self.sock.Write(ob) + } + return +} + +// Usually called in a goroutine, Start spawns a thread +// that demux's incoming netlink responses. +// Echan is used to report internal netlink errors, and may +// be set to nil (but you will likely miss bugs!) +func (self *Handler) Start(echan chan error) { + r := bufio.NewReader(self.sock) + for { + msg, err := ReadMessage(r, 4) + if err == nil { + if self.recipients[msg.Header.MessageSequence()] == nil { + if nil != echan { + echan <- errors.New(fmt.Sprintf("GoNetlink: No handler found for seq %d", + msg.Header.MessageSequence())) + } + continue + } else { + self.recipients[msg.Header.MessageSequence()] <- *msg + if msg.Header.MessageFlags()&NLM_F_MULTI == 0 { + close(self.recipients[msg.Header.MessageSequence()]) + delete(self.recipients, msg.Header.MessageSequence()) + } + } + } else { + if nil != echan { + echan <- err + } + } + } + return +} diff --git a/src/netlink/header.go b/src/netlink/header.go new file mode 100644 index 0000000..98cacaa --- /dev/null +++ b/src/netlink/header.go @@ -0,0 +1,59 @@ +package netlink + +/* + Copyright (c) 2011, Abneptis LLC. All rights reserved. + Original Author: James D. Nurmi + + See LICENSE for details +*/ + +import ( + "encoding/binary" + "errors" +) + +const HEADER_LENGTH = 16 + +// Represents the header of a netlink.Message +type Header [HEADER_LENGTH]byte + +func (self Header) Len() int { return HEADER_LENGTH } + +func (self Header) MessageLength() uint32 { return binary.LittleEndian.Uint32(self[0:4]) } +func (self *Header) SetMessageLength(in uint32) { binary.LittleEndian.PutUint32(self[0:4], in) } +func (self Header) MessageType() MessageType { + return MessageType(binary.LittleEndian.Uint16(self[4:6])) +} +func (self Header) MessageFlags() MessageFlags { + return MessageFlags(binary.LittleEndian.Uint16(self[6:8])) +} +func (self Header) MessageSequence() uint32 { return binary.LittleEndian.Uint32(self[8:12]) } +func (self *Header) SetMessageSequence(in uint32) { binary.LittleEndian.PutUint32(self[8:12], in) } +func (self Header) MessagePid() uint32 { return binary.LittleEndian.Uint32(self[12:16]) } + +func NewHeader(t MessageType, f MessageFlags, seq uint32) (h *Header) { + h = &Header{} + binary.LittleEndian.PutUint32(h[0:4], HEADER_LENGTH) + binary.LittleEndian.PutUint16(h[4:6], uint16(t)) + binary.LittleEndian.PutUint16(h[6:8], uint16(f)) + binary.LittleEndian.PutUint32(h[8:12], seq) + binary.LittleEndian.PutUint32(h[12:16], 0) + + return +} + +func (self Header) MarshalNetlink(pad int) (out []byte, err error) { + out = make([]byte, HEADER_LENGTH) + copy(out, self[0:HEADER_LENGTH]) + out = PadBytes(out, pad) + return +} + +func (self *Header) UnmarshalNetlink(in []byte, pad int) (err error) { + if len(in) != HEADER_LENGTH { + err = errors.New("Incorrect NetlinkHeader length") + } else { + copy(self[0:HEADER_LENGTH], in[0:HEADER_LENGTH]) + } + return +} diff --git a/src/netlink/message.go b/src/netlink/message.go new file mode 100644 index 0000000..482b287 --- /dev/null +++ b/src/netlink/message.go @@ -0,0 +1,72 @@ +package netlink + +/* + Copyright (c) 2011, Abneptis LLC. All rights reserved. + Original Author: James D. Nurmi + + See LICENSE for details +*/ + +import ( + "errors" + "fmt" +) +import "bytes" + +import "io" + +// A netlink message contains a Netlink header, +// and a body of bytes. +type Message struct { + Header *Header + Body []byte +} + +// NetlinkMarshaler's are used to pad and format netlink data. +type NetlinkMarshaler interface { + MarshalNetlink(int) ([]byte, error) +} + +// Creates a new message from a marshalable object +func NewMessage(t MessageType, f MessageFlags, u NetlinkMarshaler, pad int) (msg *Message, err error) { + msg = &Message{Header: NewHeader(t, f, 0)} + msg.Body, err = u.MarshalNetlink(pad) + if err == nil { + msg.Header.SetMessageLength(uint32(msg.Header.Len()) + uint32(len(msg.Body))) + } + return +} + +// Reads a message from an io.Reader, with a specified padding. +// NB: Netlink uses a very strict protocol, and it is encouraged +// that r be a bufio.Reader +func ReadMessage(r io.Reader, pad int) (msg *Message, err error) { + var n int + msg = &Message{Header: &Header{}} + ib := make([]byte, msg.Header.Len()) + n, err = r.Read(ib) + if err == nil && n != msg.Header.Len() { + err = errors.New("Incomplete netlink header") + } + if err == nil { + err = msg.Header.UnmarshalNetlink(ib, pad) + if err == nil { + msg.Body = make([]byte, msg.Header.MessageLength()-uint32(msg.Header.Len())) + n, err = r.Read(msg.Body) + if err == nil && n != int(msg.Header.MessageLength())-int(msg.Header.Len()) { + err = errors.New(fmt.Sprintf("Incomplete netlink message body (Got: %d; Expected: %d)", n, int(msg.Header.MessageLength())-int(msg.Header.Len()))) + } else { + } + } + } + return +} + +// Marshals a message with appropriate padding (generally none). +func (self Message) MarshalNetlink(pad int) (out []byte, err error) { + hdrout, err := self.Header.MarshalNetlink(pad) + if err == nil { + out = bytes.Join([][]byte{hdrout, self.Body}, []byte{}) + } + return +} diff --git a/src/pad.go b/src/netlink/pad.go similarity index 100% rename from src/pad.go rename to src/netlink/pad.go diff --git a/src/rtmanip/Makefile b/src/netlink/rtmanip/Makefile similarity index 100% rename from src/rtmanip/Makefile rename to src/netlink/rtmanip/Makefile diff --git a/src/netlink/rtmanip/links.go b/src/netlink/rtmanip/links.go new file mode 100644 index 0000000..913608a --- /dev/null +++ b/src/netlink/rtmanip/links.go @@ -0,0 +1,207 @@ +package rtmanip + +/* + Copyright (c) 2011, Abneptis LLC. All rights reserved. + Original Author: James D. Nurmi + + See LICENSE for details +*/ + +import ( + "errors" + "netlink/rtnetlink/link" +) +import "netlink/rtnetlink" +import "netlink" + +import "log" + +type LinkHandler struct { + h *netlink.Handler + cache *rtnetlink.Message +} + +func (self *LinkHandler) LinkBroadcastAddress() (s []byte) { + attr, err := self.cache.GetAttribute(link.IFLA_BROADCAST) + if err == nil { + s = attr.Body + } + return +} + +func (self *LinkHandler) LinkAddress() (s []byte) { + attr, err := self.cache.GetAttribute(link.IFLA_ADDRESS) + if err == nil { + s = attr.Body + } + return +} + +func (self *LinkHandler) Refresh() (err error) { + if hdr, ok := self.cache.Header.(*link.Header); ok { + lf := &linkFinder{h: self.h} + l, err := lf.GetLinkByID(hdr.InterfaceIndex()) + if err == nil { + *self.cache = *l.cache + } + } + return +} + +func (self *LinkHandler) LinkMTU() (i uint32) { + i, _ = netlink.GetAttributeUint32(self.cache, link.IFLA_MTU) + return +} + +func (self *LinkHandler) SetLinkState(flag link.Flags) (err error) { + var qry *netlink.Message + if hdr, ok := self.cache.Header.(*link.Header); ok { + // While rtnetlink(7) says changes should always be IFF_QUERY, it has some + // behaviours that are undocumented - like limiting actions on SETLINK's to + // specific FLAGs. + hdr = link.NewHeader(hdr.InterfaceFamily(), hdr.InterfaceType(), hdr.InterfaceIndex(), flag&link.IFF_UP, link.IFF_UP) + msg := rtnetlink.Message{Header: hdr} + qry, err = netlink.NewMessage(rtnetlink.RTM_SETLINK, netlink.NLM_F_ACK|netlink.NLM_F_REQUEST, msg, 4) + } else { + err = errors.New("Cant set link flags (invalid cache)") + } + if err != nil { + return + } + mch, err := self.h.Query(*qry, 1, 4) + if err == nil { + for m := range mch { + switch m.Header.MessageType() { + case netlink.NLMSG_ERROR: + emsg := &netlink.Error{} + err = emsg.UnmarshalNetlink(m.Body, 4) + if err == nil && emsg.Code() != 0 { + err = emsg + } + default: + err = errors.New("Unexpected netlink message") + log.Printf("NetlinkError: %v", err) + } + } + close(mch) + } + return +} + +func (self *LinkHandler) LinkFlags() (flags link.Flags) { + if hdr, ok := self.cache.Header.(*link.Header); ok { + flags = hdr.Flags() + } + return +} + +func (self *LinkHandler) LinkIndex() (i uint32) { + if hdr, ok := self.cache.Header.(*link.Header); ok { + i = hdr.InterfaceIndex() + } + return +} + +func (self *LinkHandler) LinkName() (s string) { + s, _ = netlink.GetAttributeCString(self.cache, link.IFLA_IFNAME) + return +} + +type LinkFinder interface { + GetLinkByID(uint32) (*LinkHandler, error) + GetLinkByName(string) (*LinkHandler, error) + GetLinks() ([]*LinkHandler, error) +} + +type linkFinder struct { + h *netlink.Handler +} + +func NewLinkFinder(h *netlink.Handler) LinkFinder { + return &linkFinder{h: h} +} + +func (self *linkFinder) GetLinkByName(s string) (lh *LinkHandler, err error) { + lhs, err := self.GetLinks() + for i := range lhs { + if lhs[i].LinkName() == s { + lh = lhs[i] + break + } + } + if lh == nil { + err = errors.New("Interface not found") + } + return +} + +func (self *linkFinder) GetLinkByID(i uint32) (lh *LinkHandler, err error) { + qry, err := netlink.NewMessage(rtnetlink.RTM_GETLINK, netlink.NLM_F_REQUEST, + link.NewHeader(rtnetlink.AF_UNSPEC, 0, i, 0, 0), 4) + if err == nil { + var mch chan netlink.Message + mch, err = self.h.Query(*qry, 1, 4) + if err == nil { + for ii := range mch { + switch ii.Header.MessageType() { + default: + err = errors.New("Unknown message type in response to RTM_GETLINK") + case netlink.NLMSG_ERROR: + emsg := &netlink.Error{} + err = emsg.UnmarshalNetlink(ii.Body, 4) + if err == nil && emsg.Code() != 0 { + err = emsg + } + case rtnetlink.RTM_NEWLINK: + lhdr := &link.Header{} + msg := &rtnetlink.Message{Header: lhdr} + err = msg.UnmarshalNetlink(ii.Body, 4) + if err == nil { + lh = &LinkHandler{h: self.h, cache: msg} + } + } + } + close(mch) + } + } + return +} + +func (self *linkFinder) GetLinks() (lhs []*LinkHandler, err error) { + qry, err := netlink.NewMessage(rtnetlink.RTM_GETLINK, netlink.NLM_F_REQUEST|netlink.NLM_F_ROOT, + link.NewHeader(rtnetlink.AF_UNSPEC, 0, 0, 0, 0), 4) + if err != nil { + return + } + var mch chan netlink.Message + mch, err = self.h.Query(*qry, 1, 4) + if err == nil { + for ii := range mch { + if ii.Header.MessageType() == netlink.NLMSG_DONE { + break + } + switch ii.Header.MessageType() { + default: + err = errors.New("Unknown message type in response to RTM_GETLINK") + case netlink.NLMSG_ERROR: + emsg := &netlink.Error{} + err = emsg.UnmarshalNetlink(ii.Body, 4) + if err == nil && emsg.Code() != 0 { + err = emsg + } + case rtnetlink.RTM_NEWLINK: + lhdr := &link.Header{} + msg := &rtnetlink.Message{Header: lhdr} + err = msg.UnmarshalNetlink(ii.Body, 4) + if err == nil { + lhs = append(lhs, &LinkHandler{h: self.h, cache: msg}) + } + } + if err != nil { + log.Printf("Internal netlink failure: %v", err) + } + } + } + close(mch) + return +} diff --git a/src/rtnetlink/Makefile b/src/netlink/rtnetlink/Makefile similarity index 100% rename from src/rtnetlink/Makefile rename to src/netlink/rtnetlink/Makefile diff --git a/src/rtnetlink/README b/src/netlink/rtnetlink/README similarity index 100% rename from src/rtnetlink/README rename to src/netlink/rtnetlink/README diff --git a/src/rtnetlink/addr/Makefile b/src/netlink/rtnetlink/addr/Makefile similarity index 100% rename from src/rtnetlink/addr/Makefile rename to src/netlink/rtnetlink/addr/Makefile diff --git a/src/rtnetlink/addr/attribute_types.go b/src/netlink/rtnetlink/addr/attribute_types.go similarity index 100% rename from src/rtnetlink/addr/attribute_types.go rename to src/netlink/rtnetlink/addr/attribute_types.go diff --git a/src/rtnetlink/addr/flags.go b/src/netlink/rtnetlink/addr/flags.go similarity index 100% rename from src/rtnetlink/addr/flags.go rename to src/netlink/rtnetlink/addr/flags.go diff --git a/src/netlink/rtnetlink/addr/header.go b/src/netlink/rtnetlink/addr/header.go new file mode 100644 index 0000000..74ce755 --- /dev/null +++ b/src/netlink/rtnetlink/addr/header.go @@ -0,0 +1,46 @@ +package addr + +/* + Copyright (c) 2011, Abneptis LLC. All rights reserved. + Original Author: James D. Nurmi + + See LICENSE for details +*/ + +import ( + "encoding/binary" + "errors" +) +import "netlink/rtnetlink" +import "netlink" + +const HEADER_LENGTH = 8 + +type Header [HEADER_LENGTH]byte + +func NewHeader(afam rtnetlink.Family, pl uint8, fl Flags, scope rtnetlink.Scope, ifindex uint32) *Header { + hdr := Header{byte(afam), pl, byte(fl), byte(scope)} + binary.LittleEndian.PutUint32(hdr[4:8], ifindex) + return &hdr +} + +func (self Header) Len() int { return HEADER_LENGTH } +func (self Header) AddressFamily() rtnetlink.Family { return rtnetlink.Family(self[0]) } +func (self Header) PrefixLength() uint8 { return self[1] } +func (self Header) Flags() Flags { return Flags(self[2]) } +func (self Header) Scope() rtnetlink.Scope { return rtnetlink.Scope(self[3]) } +func (self Header) InterfaceIndex() uint32 { return binary.LittleEndian.Uint32(self[4:8]) } + +func (self *Header) UnmarshalNetlink(in []byte, pad int) (err error) { + if len(in) != HEADER_LENGTH { + err = errors.New("Wrong length for Header") + } else { + copy(self[0:HEADER_LENGTH], in[0:HEADER_LENGTH]) + } + return +} + +func (self Header) MarshalNetlink(pad int) (out []byte, err error) { + out = netlink.PadBytes(self[0:HEADER_LENGTH], pad) + return +} diff --git a/src/rtnetlink/family.go b/src/netlink/rtnetlink/family.go similarity index 100% rename from src/rtnetlink/family.go rename to src/netlink/rtnetlink/family.go diff --git a/src/rtnetlink/groups.go b/src/netlink/rtnetlink/groups.go similarity index 100% rename from src/rtnetlink/groups.go rename to src/netlink/rtnetlink/groups.go diff --git a/src/rtnetlink/header.go b/src/netlink/rtnetlink/header.go similarity index 66% rename from src/rtnetlink/header.go rename to src/netlink/rtnetlink/header.go index 1f92699..a4bdccc 100644 --- a/src/rtnetlink/header.go +++ b/src/netlink/rtnetlink/header.go @@ -1,4 +1,5 @@ package rtnetlink + /* Copyright (c) 2011, Abneptis LLC. All rights reserved. Original Author: James D. Nurmi @@ -6,12 +7,10 @@ package rtnetlink See LICENSE for details */ -import "os" - // An RTNetlink Header describes the structures // between the netlink header and the nlattributes. type Header interface { - Len()(int) // The (unpadded) length of the Header. - UnmarshalNetlink([]byte, int)(os.Error) - MarshalNetlink(int)([]byte, os.Error) + Len() int // The (unpadded) length of the Header. + UnmarshalNetlink([]byte, int) error + MarshalNetlink(int) ([]byte, error) } diff --git a/src/rtnetlink/link/Makefile b/src/netlink/rtnetlink/link/Makefile similarity index 100% rename from src/rtnetlink/link/Makefile rename to src/netlink/rtnetlink/link/Makefile diff --git a/src/rtnetlink/link/attribute_types.go b/src/netlink/rtnetlink/link/attribute_types.go similarity index 100% rename from src/rtnetlink/link/attribute_types.go rename to src/netlink/rtnetlink/link/attribute_types.go diff --git a/src/rtnetlink/link/flags.go b/src/netlink/rtnetlink/link/flags.go similarity index 100% rename from src/rtnetlink/link/flags.go rename to src/netlink/rtnetlink/link/flags.go diff --git a/src/netlink/rtnetlink/link/header.go b/src/netlink/rtnetlink/link/header.go new file mode 100644 index 0000000..66eb556 --- /dev/null +++ b/src/netlink/rtnetlink/link/header.go @@ -0,0 +1,51 @@ +package link + +/* + Copyright (c) 2011, Abneptis LLC. All rights reserved. + Original Author: James D. Nurmi + + See LICENSE for details +*/ + +import "netlink" +import "netlink/rtnetlink" + +import ( + "encoding/binary" + "errors" +) + +const HEADER_LENGTH = 16 + +type Header [16]byte + +func NewHeader(fam rtnetlink.Family, itype uint16, iindex uint32, flags, changes Flags) (hdr *Header) { + hdr = &Header{byte(fam)} + binary.LittleEndian.PutUint16(hdr[2:4], itype) + binary.LittleEndian.PutUint32(hdr[4:8], iindex) + binary.LittleEndian.PutUint32(hdr[8:12], uint32(flags)) + binary.LittleEndian.PutUint32(hdr[12:16], uint32(changes)) + return +} + +func (self Header) Len() int { return HEADER_LENGTH } +func (self *Header) UnmarshalNetlink(in []byte, pad int) (err error) { + if len(in) != HEADER_LENGTH { + err = errors.New("Wrong length for Header") + } else { + copy(self[0:HEADER_LENGTH], in[0:HEADER_LENGTH]) + } + return +} + +func (self Header) MarshalNetlink(pad int) (out []byte, err error) { + out = netlink.PadBytes(self[0:HEADER_LENGTH], pad) + return +} + +func (self Header) Flags() Flags { return Flags(binary.LittleEndian.Uint32(self[8:12])) } +func (self *Header) SetFlags(f Flags) { binary.LittleEndian.PutUint32(self[8:12], uint32(f)) } +func (self Header) InterfaceFamily() rtnetlink.Family { return rtnetlink.Family(self[0]) } +func (self Header) InterfaceType() uint16 { return binary.LittleEndian.Uint16(self[2:4]) } +func (self Header) InterfaceIndex() uint32 { return binary.LittleEndian.Uint32(self[4:8]) } +func (self Header) InterfaceChanges() Flags { return Flags(binary.LittleEndian.Uint32(self[12:16])) } diff --git a/src/netlink/rtnetlink/message.go b/src/netlink/rtnetlink/message.go new file mode 100644 index 0000000..de3da0e --- /dev/null +++ b/src/netlink/rtnetlink/message.go @@ -0,0 +1,85 @@ +package rtnetlink + +/* + Copyright (c) 2011, Abneptis LLC. All rights reserved. + Original Author: James D. Nurmi + + See LICENSE for details +*/ + +import ( + "bytes" + "errors" +) +import "netlink" + +// A Message contains a Header object and a series of attributes. +// It is extracted from the Body of a netlink.Message +type Message struct { + Header Header + Attributes []netlink.Attribute +} + +// Create a new rtnetlink.Message based off of a header an list of attributes +// (which may be nil or empty). +func NewMessage(h Header, attrs []netlink.Attribute) *Message { + return &Message{Header: h, Attributes: attrs} +} + +// Replace or append the attribute with the AttributeType of +// attr +func (self *Message) SetAttribute(attr netlink.Attribute) { + t := attr.Type + for i := range self.Attributes { + if t == self.Attributes[i].Type { + self.Attributes[i] = attr + return + } + } + self.Attributes = append(self.Attributes, attr) + return +} + +// Retrieve (the first) Attribute identified by Type, +// returning an error if not found. +func (self Message) GetAttribute(t netlink.AttributeType) (attr netlink.Attribute, err error) { + for i := range self.Attributes { + if t == self.Attributes[i].Type { + attr = self.Attributes[i] + return + } + } + err = errors.New("Attribute not found") + return +} + +// Handles the appropriate calls to marshal the Header and Attribute values, +// and return an appropriately padded result. +func (self Message) MarshalNetlink(pad int) (out []byte, err error) { + hb, err := self.Header.MarshalNetlink(pad) + if err == nil { + var bb []byte + bb, err = netlink.MarshalAttributes(self.Attributes, pad) + if err == nil { + out = bytes.Join([][]byte{hb, bb}, []byte{}) + } + } + return +} + +// Unmarshals a generic message using the header as a guide. +// An error will be returned if the header cannot unmarshal properly, +// or any attribute in the series failed. +func (self *Message) UnmarshalNetlink(in []byte, pad int) (err error) { + if len(in) < self.Header.Len() { + return errors.New("Insufficient data for unmarshal of Header") + } + err = self.Header.UnmarshalNetlink(in[0:self.Header.Len()], pad) + if err == nil { + pos := netlink.Reposition(self.Header.Len(), pad) + if len(in) > pos { + self.Attributes, err = netlink.UnmarshalAttributes(in[pos:], pad) + } + } + return +} diff --git a/src/rtnetlink/message_types.go b/src/netlink/rtnetlink/message_types.go similarity index 100% rename from src/rtnetlink/message_types.go rename to src/netlink/rtnetlink/message_types.go diff --git a/src/rtnetlink/route/Makefile b/src/netlink/rtnetlink/route/Makefile similarity index 100% rename from src/rtnetlink/route/Makefile rename to src/netlink/rtnetlink/route/Makefile diff --git a/src/rtnetlink/route/attribute_types.go b/src/netlink/rtnetlink/route/attribute_types.go similarity index 100% rename from src/rtnetlink/route/attribute_types.go rename to src/netlink/rtnetlink/route/attribute_types.go diff --git a/src/rtnetlink/route/flags.go b/src/netlink/rtnetlink/route/flags.go similarity index 100% rename from src/rtnetlink/route/flags.go rename to src/netlink/rtnetlink/route/flags.go diff --git a/src/netlink/rtnetlink/route/header.go b/src/netlink/rtnetlink/route/header.go new file mode 100644 index 0000000..965b3ae --- /dev/null +++ b/src/netlink/rtnetlink/route/header.go @@ -0,0 +1,53 @@ +package route + +/* + Copyright (c) 2011, Abneptis LLC. All rights reserved. + Original Author: James D. Nurmi + + See LICENSE for details +*/ + +import ( + "encoding/binary" + "errors" +) +import "netlink/rtnetlink" +import "netlink" + +type Header [12]byte + +func NewHeader(afam rtnetlink.Family, dl uint8, sl uint8, tos uint8, t Table, o Origin, s rtnetlink.Scope, T Type, f Flags) *Header { + hdr := Header{byte(afam), dl, sl, tos, byte(t), byte(o), byte(s), byte(T)} + binary.LittleEndian.PutUint32(hdr[8:12], uint32(f)) + return &hdr +} + +func (self Header) Len() int { return 12 } +func (self Header) AddressFamily() rtnetlink.Family { return rtnetlink.Family(self[0]) } +func (self Header) AddressDestLength() uint8 { return self[1] } +func (self Header) AddressSourceLength() uint8 { return self[2] } +func (self Header) TOS() uint8 { return self[3] } +func (self Header) RoutingTable() Table { return Table(self[4]) } +func (self Header) RouteOrigin() Origin { return Origin(self[5]) } +func (self Header) AddressScope() rtnetlink.Scope { return rtnetlink.Scope(self[6]) } +func (self Header) RouteType() Type { return Type(self[7]) } +func (self Header) Flags() Flags { return Flags(binary.LittleEndian.Uint32(self[8:12])) } + +func (self *Header) UnmarshalNetlink(in []byte, pad int) (err error) { + if len(in) < 12 { + err = errors.New("Too short to be a valid Routing Message") + } + if err == nil { + copy(self[0:12], in[0:12]) + } + return +} + +func (self Header) MarshalNetlink(pad int) (out []byte, err error) { + if err == nil { + out = make([]byte, 12) + copy(out, self[0:]) + out = netlink.PadBytes(out, pad) + } + return +} diff --git a/src/rtnetlink/route/origin.go b/src/netlink/rtnetlink/route/origin.go similarity index 100% rename from src/rtnetlink/route/origin.go rename to src/netlink/rtnetlink/route/origin.go diff --git a/src/rtnetlink/route/table.go b/src/netlink/rtnetlink/route/table.go similarity index 100% rename from src/rtnetlink/route/table.go rename to src/netlink/rtnetlink/route/table.go diff --git a/src/rtnetlink/route/types.go b/src/netlink/rtnetlink/route/types.go similarity index 100% rename from src/rtnetlink/route/types.go rename to src/netlink/rtnetlink/route/types.go diff --git a/src/rtnetlink/scope.go b/src/netlink/rtnetlink/scope.go similarity index 100% rename from src/rtnetlink/scope.go rename to src/netlink/rtnetlink/scope.go diff --git a/src/socket.go b/src/netlink/socket.go similarity index 50% rename from src/socket.go rename to src/netlink/socket.go index 3969fe9..9392ef4 100644 --- a/src/socket.go +++ b/src/netlink/socket.go @@ -7,59 +7,48 @@ package netlink See LICENSE for details */ -import "os" import "syscall" // A netlink.Socket implements the lowest level of netlink communications. type Socket struct { - fd int -} - -func toErr(eno int)(err os.Error){ - if eno != 0 { err = os.NewError(syscall.Errstr(eno))} - return + fd int } // Dials a netlink socket. Usually you do not need permissions for this, // though specific commands may be rejected. -func Dial(nlf NetlinkFamily)(rwc *Socket, err os.Error){ - fdno, errno := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_DGRAM, int(nlf)) - err = toErr(errno) - if err == nil { - rwc = &Socket{fd:fdno} - } - return +func Dial(nlf NetlinkFamily) (rwc *Socket, err error) { + fdno, err := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_DGRAM, int(nlf)) +// err = toErr(errno) + if err == nil { + rwc = &Socket{fd: fdno} + } + return } // Close the netlink socket -func (self *Socket)Close()(err os.Error){ - errno := syscall.Close(self.fd) - err = toErr(errno) - return +func (self *Socket) Close() (err error) { + syscall.Close(self.fd) + //err = toErr(errno) + return } // Writes to the netlink socket. Data should be (1 or more) complete // netlink frames, as netlink is not friendly w/ fragmentation. -func (self *Socket)Write(in []byte)(n int, err os.Error){ - n, errno := syscall.Write(self.fd, in) - err = toErr(errno) - return +func (self *Socket) Write(in []byte) (n int, err error) { + n, err = syscall.Write(self.fd, in) + return } // Reads from a netlink socket. Generally should be a bufio with // at least an 8k buffer. More for machines with large routing tables. -func (self *Socket)Read(in []byte)(n int, err os.Error){ - n, errno := syscall.Read(self.fd, in) - err = toErr(errno) - return +func (self *Socket) Read(in []byte) (n int, err error) { + n, err = syscall.Read(self.fd, in) + return } // Bind the netlink socket to receive multicast messages -func (self *Socket)Bind(pid, groups uint32) (err os.Error) { +func (self *Socket) Bind(pid, groups uint32) (err error) { addr := &syscall.SockaddrNetlink{Pid: pid, Groups: groups} - e := syscall.Bind(self.fd, addr) - if e != 0 { - err = os.Errno(e) - } + err = syscall.Bind(self.fd, addr) return -} \ No newline at end of file +} diff --git a/src/types.go b/src/netlink/types.go similarity index 100% rename from src/types.go rename to src/netlink/types.go diff --git a/src/rtmanip/links.go b/src/rtmanip/links.go deleted file mode 100644 index 6b94396..0000000 --- a/src/rtmanip/links.go +++ /dev/null @@ -1,184 +0,0 @@ -package rtmanip -/* - Copyright (c) 2011, Abneptis LLC. All rights reserved. - Original Author: James D. Nurmi - - See LICENSE for details -*/ - -import "netlink/rtnetlink/link" -import "netlink/rtnetlink" -import "netlink" -import "os" -import "log" - -type LinkHandler struct { - h *netlink.Handler - cache *rtnetlink.Message -} - -func (self *LinkHandler)LinkBroadcastAddress()(s []byte){ - attr, err := self.cache.GetAttribute(link.IFLA_BROADCAST) - if err == nil { - s = attr.Body - } - return -} - -func (self *LinkHandler)LinkAddress()(s []byte){ - attr, err := self.cache.GetAttribute(link.IFLA_ADDRESS) - if err == nil { - s = attr.Body - } - return -} - -func (self *LinkHandler)Refresh()(err os.Error){ - if hdr, ok := self.cache.Header.(*link.Header); ok { - lf := &linkFinder{h: self.h} - l, err := lf.GetLinkByID(hdr.InterfaceIndex()) - if err == nil { - *self.cache = *l.cache - } - } - return -} - -func (self *LinkHandler)LinkMTU()(i uint32){ - i, _ = netlink.GetAttributeUint32(self.cache, link.IFLA_MTU) - return -} - -func (self *LinkHandler)SetLinkState(flag link.Flags)(err os.Error){ - var qry *netlink.Message - if hdr, ok := self.cache.Header.(*link.Header); ok { - // While rtnetlink(7) says changes should always be IFF_QUERY, it has some - // behaviours that are undocumented - like limiting actions on SETLINK's to - // specific FLAGs. - hdr = link.NewHeader(hdr.InterfaceFamily(), hdr.InterfaceType(), hdr.InterfaceIndex(), flag & link.IFF_UP, link.IFF_UP) - msg := rtnetlink.Message{Header: hdr} - qry, err = netlink.NewMessage(rtnetlink.RTM_SETLINK, netlink.NLM_F_ACK|netlink.NLM_F_REQUEST, msg, 4) - } else { - err = os.NewError("Cant set link flags (invalid cache)") - } - if err != nil { return } - mch, err := self.h.Query(*qry,1, 4) - if err == nil { - for m := range(mch) { - switch m.Header.MessageType() { - case netlink.NLMSG_ERROR: - emsg := &netlink.Error{} - err = emsg.UnmarshalNetlink(m.Body, 4) - if err == nil && emsg.Code() != 0 { err = emsg } - default: - err = os.NewError("Unexpected netlink message") - log.Printf("NetlinkError: %v", err) - } - } - close(mch) - } - return -} - -func (self *LinkHandler)LinkFlags()(flags link.Flags){ - if hdr, ok := self.cache.Header.(*link.Header); ok { - flags = hdr.Flags() - } - return -} - -func (self *LinkHandler)LinkIndex()(i uint32){ - if hdr, ok := self.cache.Header.(*link.Header); ok { - i = hdr.InterfaceIndex() - } - return -} - -func (self *LinkHandler)LinkName()(s string){ - s, _ = netlink.GetAttributeCString(self.cache, link.IFLA_IFNAME) - return -} - -type LinkFinder interface { - GetLinkByID(uint32)(*LinkHandler, os.Error) - GetLinkByName(string)(*LinkHandler, os.Error) - GetLinks()([]*LinkHandler, os.Error) -} - -type linkFinder struct { - h *netlink.Handler -} - -func NewLinkFinder(h *netlink.Handler)(LinkFinder){ - return &linkFinder{h:h} -} - -func (self *linkFinder)GetLinkByName(s string)(lh *LinkHandler, err os.Error){ - lhs, err := self.GetLinks() - for i := range(lhs) { - if lhs[i].LinkName() == s { - lh = lhs[i] - break - } - } - if lh == nil { err = os.NewError("Interface not found")} - return -} - -func (self *linkFinder)GetLinkByID(i uint32)(lh *LinkHandler, err os.Error){ - qry, err := netlink.NewMessage(rtnetlink.RTM_GETLINK, netlink.NLM_F_REQUEST, - link.NewHeader(rtnetlink.AF_UNSPEC, 0, i, 0,0), 4) - if err == nil { - var mch chan netlink.Message - mch, err = self.h.Query(*qry,1, 4) - if err == nil { - for ii := range(mch) { - switch ii.Header.MessageType(){ - default: err = os.NewError("Unknown message type in response to RTM_GETLINK") - case netlink.NLMSG_ERROR: - emsg := &netlink.Error{} - err = emsg.UnmarshalNetlink(ii.Body, 4) - if err == nil && emsg.Code() != 0 { err = emsg } - case rtnetlink.RTM_NEWLINK: - lhdr := &link.Header{} - msg := &rtnetlink.Message{Header: lhdr} - err = msg.UnmarshalNetlink(ii.Body, 4) - if err == nil { lh = &LinkHandler{h: self.h, cache: msg} } - } - } - close(mch) - } - } - return -} - -func (self *linkFinder)GetLinks()(lhs []*LinkHandler, err os.Error){ - qry, err := netlink.NewMessage(rtnetlink.RTM_GETLINK, netlink.NLM_F_REQUEST|netlink.NLM_F_ROOT, - link.NewHeader(rtnetlink.AF_UNSPEC, 0, 0, 0,0), 4) - if err != nil { return } - var mch chan netlink.Message - mch, err = self.h.Query(*qry,1, 4) - if err == nil { - for ii := range(mch) { - if ii.Header.MessageType() == netlink.NLMSG_DONE { break } - switch ii.Header.MessageType(){ - default: - err = os.NewError("Unknown message type in response to RTM_GETLINK") - case netlink.NLMSG_ERROR: - emsg := &netlink.Error{} - err = emsg.UnmarshalNetlink(ii.Body, 4) - if err == nil && emsg.Code() != 0 { err = emsg } - case rtnetlink.RTM_NEWLINK: - lhdr := &link.Header{} - msg := &rtnetlink.Message{Header: lhdr} - err = msg.UnmarshalNetlink(ii.Body, 4) - if err == nil { - lhs = append(lhs, &LinkHandler{h: self.h, cache: msg}) - } - } - if err != nil { log.Printf("Internal netlink failure: %v", err) } - } - } - close(mch) - return -} diff --git a/src/rtnetlink/addr/header.go b/src/rtnetlink/addr/header.go deleted file mode 100644 index f99de11..0000000 --- a/src/rtnetlink/addr/header.go +++ /dev/null @@ -1,44 +0,0 @@ -package addr -/* - Copyright (c) 2011, Abneptis LLC. All rights reserved. - Original Author: James D. Nurmi - - See LICENSE for details -*/ - -import "encoding/binary" -import "netlink/rtnetlink" -import "netlink" -import "os" - - -const HEADER_LENGTH = 8 -type Header [HEADER_LENGTH]byte - -func NewHeader(afam rtnetlink.Family, pl uint8, fl Flags, scope rtnetlink.Scope, ifindex uint32)(*Header){ - hdr := Header{byte(afam), pl, byte(fl), byte(scope)} - binary.LittleEndian.PutUint32(hdr[4:8], ifindex) - return &hdr -} - - -func (self Header)Len()(int){ return HEADER_LENGTH } -func (self Header)AddressFamily()(rtnetlink.Family){ return rtnetlink.Family(self[0]) } -func (self Header)PrefixLength()(uint8){ return self[1] } -func (self Header)Flags()(Flags){ return Flags(self[2]) } -func (self Header)Scope()(rtnetlink.Scope){ return rtnetlink.Scope(self[3]) } -func (self Header)InterfaceIndex()(uint32){ return binary.LittleEndian.Uint32(self[4:8]) } - -func (self *Header)UnmarshalNetlink(in []byte, pad int)(err os.Error){ - if len(in) != HEADER_LENGTH { - err = os.NewError("Wrong length for Header") - } else { - copy(self[0:HEADER_LENGTH], in[0:HEADER_LENGTH]) - } - return -} - -func (self Header)MarshalNetlink(pad int)(out []byte, err os.Error){ - out = netlink.PadBytes(self[0:HEADER_LENGTH], pad) - return -} diff --git a/src/rtnetlink/link/header.go b/src/rtnetlink/link/header.go deleted file mode 100644 index 595da82..0000000 --- a/src/rtnetlink/link/header.go +++ /dev/null @@ -1,48 +0,0 @@ -package link -/* - Copyright (c) 2011, Abneptis LLC. All rights reserved. - Original Author: James D. Nurmi - - See LICENSE for details -*/ - -import "netlink" -import "netlink/rtnetlink" -import "os" -import "encoding/binary" - - -const HEADER_LENGTH = 16 -type Header [16]byte - -func NewHeader(fam rtnetlink.Family, itype uint16, iindex uint32, flags, changes Flags)(hdr *Header){ - hdr = &Header{byte(fam)} - binary.LittleEndian.PutUint16(hdr[2:4], itype) - binary.LittleEndian.PutUint32(hdr[4:8], iindex) - binary.LittleEndian.PutUint32(hdr[8:12], uint32(flags)) - binary.LittleEndian.PutUint32(hdr[12:16], uint32(changes)) - return -} - -func (self Header)Len()(int) { return HEADER_LENGTH } -func (self *Header)UnmarshalNetlink(in []byte, pad int)(err os.Error){ - if len(in) != HEADER_LENGTH { - err = os.NewError("Wrong length for Header") - } else { - copy(self[0:HEADER_LENGTH], in[0:HEADER_LENGTH]) - } - return -} - -func (self Header)MarshalNetlink(pad int)(out []byte, err os.Error){ - out = netlink.PadBytes(self[0:HEADER_LENGTH], pad) - return -} - -func (self Header)Flags()(Flags){ return Flags(binary.LittleEndian.Uint32(self[8:12])) } -func (self *Header)SetFlags(f Flags){ binary.LittleEndian.PutUint32(self[8:12], uint32(f)) } -func (self Header)InterfaceFamily()(rtnetlink.Family){ return rtnetlink.Family(self[0])} -func (self Header)InterfaceType()(uint16){ return binary.LittleEndian.Uint16(self[2:4]) } -func (self Header)InterfaceIndex()(uint32){ return binary.LittleEndian.Uint32(self[4:8]) } -func (self Header)InterfaceChanges()(Flags){ return Flags(binary.LittleEndian.Uint32(self[12:16])) } - diff --git a/src/rtnetlink/message.go b/src/rtnetlink/message.go deleted file mode 100644 index d79d8d9..0000000 --- a/src/rtnetlink/message.go +++ /dev/null @@ -1,82 +0,0 @@ -package rtnetlink -/* - Copyright (c) 2011, Abneptis LLC. All rights reserved. - Original Author: James D. Nurmi - - See LICENSE for details -*/ - -import "bytes" -import "netlink" -import "os" - -// A Message contains a Header object and a series of attributes. -// It is extracted from the Body of a netlink.Message -type Message struct { - Header Header - Attributes []netlink.Attribute -} - -// Create a new rtnetlink.Message based off of a header an list of attributes -// (which may be nil or empty). -func NewMessage(h Header, attrs []netlink.Attribute)(*Message){ - return &Message{Header:h, Attributes: attrs} -} - -// Replace or append the attribute with the AttributeType of -// attr -func (self *Message)SetAttribute(attr netlink.Attribute){ - t := attr.Type - for i := range(self.Attributes){ - if t == self.Attributes[i].Type { - self.Attributes[i] = attr - return - } - } - self.Attributes = append(self.Attributes, attr) - return -} - -// Retrieve (the first) Attribute identified by Type, -// returning an error if not found. -func (self Message)GetAttribute(t netlink.AttributeType)(attr netlink.Attribute, err os.Error){ - for i := range(self.Attributes){ - if t == self.Attributes[i].Type { - attr = self.Attributes[i] - return - } - } - err = os.NewError("Attribute not found") - return -} - -// Handles the appropriate calls to marshal the Header and Attribute values, -// and return an appropriately padded result. -func (self Message)MarshalNetlink(pad int)(out []byte, err os.Error){ - hb, err := self.Header.MarshalNetlink(pad) - if err == nil { - var bb []byte - bb, err = netlink.MarshalAttributes(self.Attributes, pad) - if err == nil { - out = bytes.Join([][]byte{ hb, bb }, []byte{} ) - } - } - return -} - -// Unmarshals a generic message using the header as a guide. -// An error will be returned if the header cannot unmarshal properly, -// or any attribute in the series failed. -func (self *Message)UnmarshalNetlink(in []byte, pad int)(err os.Error){ - if len(in) < self.Header.Len() { - return os.NewError("Insufficient data for unmarshal of Header") - } - err = self.Header.UnmarshalNetlink(in[0:self.Header.Len()], pad) - if err == nil { - pos := netlink.Reposition(self.Header.Len(), pad) - if len(in) > pos { - self.Attributes, err = netlink.UnmarshalAttributes(in[pos:], pad) - } - } - return -} diff --git a/src/rtnetlink/route/header.go b/src/rtnetlink/route/header.go deleted file mode 100644 index 8fe9e22..0000000 --- a/src/rtnetlink/route/header.go +++ /dev/null @@ -1,53 +0,0 @@ -package route -/* - Copyright (c) 2011, Abneptis LLC. All rights reserved. - Original Author: James D. Nurmi - - See LICENSE for details -*/ - -import "encoding/binary" -import "netlink/rtnetlink" -import "netlink" -import "os" - - -type Header [12]byte - -func NewHeader(afam rtnetlink.Family, dl uint8, sl uint8, tos uint8, t Table, o Origin, s rtnetlink.Scope, T Type, f Flags)(*Header){ - hdr := Header{byte(afam), dl, sl, tos, byte(t), byte(o), byte(s), byte(T)} - binary.LittleEndian.PutUint32(hdr[8:12], uint32(f)) - return &hdr -} - - -func (self Header)Len()(int) { return 12 } -func (self Header)AddressFamily()(rtnetlink.Family){ return rtnetlink.Family(self[0]) } -func (self Header)AddressDestLength()(uint8){ return self[1] } -func (self Header)AddressSourceLength()(uint8){ return self[2] } -func (self Header)TOS()(uint8){ return self[3] } -func (self Header)RoutingTable()(Table){ return Table(self[4]) } -func (self Header)RouteOrigin()(Origin){ return Origin(self[5]) } -func (self Header)AddressScope()(rtnetlink.Scope){ return rtnetlink.Scope(self[6]) } -func (self Header)RouteType()(Type){ return Type(self[7]) } -func (self Header)Flags()(Flags) { return Flags(binary.LittleEndian.Uint32(self[8:12])) } - - -func (self *Header)UnmarshalNetlink(in []byte, pad int)(err os.Error){ - if len(in) < 12 { - err = os.NewError("Too short to be a valid Routing Message") - } - if err == nil { - copy(self[0:12], in[0:12]) - } - return -} - -func (self Header)MarshalNetlink(pad int)(out []byte, err os.Error){ - if err == nil { - out = make([]byte, 12) - copy(out, self[0:]) - out = netlink.PadBytes(out, pad) - } - return -} diff --git a/tools/get_addrs.go b/tools/get_addrs.go index f37c323..e791b92 100644 --- a/tools/get_addrs.go +++ b/tools/get_addrs.go @@ -10,61 +10,62 @@ package main See LICENSE for details */ -import "os" import "netlink/rtnetlink/addr" import "netlink/rtnetlink" import "log" import "netlink" -func logec(c chan os.Error){ - for i := range(c) { - log.Printf("Error: %v", i) - } +func logec(c chan error) { + for i := range c { + log.Printf("Error: %v", i) + } } -func main(){ - nlmsg, err := netlink.NewMessage(rtnetlink.RTM_GETADDR, netlink.NLM_F_DUMP|netlink.NLM_F_REQUEST, &addr.Header{}, 4) - if err != nil { - log.Exitf("Couldn't construct message: %v", err) - } - log.Printf("Dialing: %v", nlmsg) - nlsock, err := netlink.Dial(netlink.NETLINK_ROUTE) - if err != nil { - log.Exitf("Couldn't dial netlink: %v", err) - } - h := netlink.NewHandler(nlsock) - ec := make(chan os.Error) - go logec(ec) - go h.Start(ec) - log.Printf("Sending query: %v", nlmsg) - c, err := h.Query(*nlmsg, 1, 4) - log.Printf("Sent query: %v", nlmsg.Header) - if err != nil { - log.Exitf("Couldn't write netlink: %v", err) - } - for i := range( c) { - if i.Header.MessageType() == netlink.NLMSG_DONE { break } - switch i.Header.MessageType() { - case rtnetlink.RTM_NEWADDR: - hdr := &addr.Header{} - msg := rtnetlink.NewMessage(hdr, nil) - err = msg.UnmarshalNetlink(i.Body, 4) - if err == nil { - log.Printf("Family: %v; Length: %d; Flags: %v; Scope: %v; IFIndex: %d", - hdr.AddressFamily(), hdr.PrefixLength(), hdr.Flags(), hdr.Scope(), - hdr.InterfaceIndex()) +func main() { + nlmsg, err := netlink.NewMessage(rtnetlink.RTM_GETADDR, netlink.NLM_F_DUMP|netlink.NLM_F_REQUEST, &addr.Header{}, 4) + if err != nil { + log.Fatalf("Couldn't construct message: %v", err) + } + log.Printf("Dialing: %v", nlmsg) + nlsock, err := netlink.Dial(netlink.NETLINK_ROUTE) + if err != nil { + log.Fatalf("Couldn't dial netlink: %v", err) + } + h := netlink.NewHandler(nlsock) + ec := make(chan error) + go logec(ec) + go h.Start(ec) + log.Printf("Sending query: %v", nlmsg) + c, err := h.Query(*nlmsg, 1, 4) + log.Printf("Sent query: %v", nlmsg.Header) + if err != nil { + log.Fatalf("Couldn't write netlink: %v", err) + } + for i := range c { + if i.Header.MessageType() == netlink.NLMSG_DONE { + break + } + switch i.Header.MessageType() { + case rtnetlink.RTM_NEWADDR: + hdr := &addr.Header{} + msg := rtnetlink.NewMessage(hdr, nil) + err = msg.UnmarshalNetlink(i.Body, 4) + if err == nil { + log.Printf("Family: %v; Length: %d; Flags: %v; Scope: %v; IFIndex: %d", + hdr.AddressFamily(), hdr.PrefixLength(), hdr.Flags(), hdr.Scope(), + hdr.InterfaceIndex()) - for i := range(msg.Attributes) { - log.Printf("Attribute[%d] = %v", i, msg.Attributes[i]) - } - } else { - log.Printf("Unmarshal error: %v", err) - } - default: - log.Printf("Unknown type: %v", i) - } - if err != nil { - log.Printf("Handler error: %v", err) - } - } + for i := range msg.Attributes { + log.Printf("Attribute[%d] = %v", i, msg.Attributes[i]) + } + } else { + log.Printf("Unmarshal error: %v", err) + } + default: + log.Printf("Unknown type: %v", i) + } + if err != nil { + log.Printf("Handler error: %v", err) + } + } } diff --git a/tools/get_links.go b/tools/get_links.go index 643536f..a163143 100644 --- a/tools/get_links.go +++ b/tools/get_links.go @@ -10,48 +10,49 @@ package main See LICENSE for details */ -import "os" import "netlink/rtnetlink/link" import "netlink/rtnetlink" import "log" import "netlink" -func main(){ - nlmsg, err := netlink.NewMessage(rtnetlink.RTM_GETLINK, netlink.NLM_F_DUMP|netlink.NLM_F_REQUEST, &link.Header{},4) - if err != nil { - log.Exitf("Couldn't construct message: %v", err) - } - nlsock, err := netlink.Dial(netlink.NETLINK_ROUTE) - if err != nil { - log.Exitf("Couldn't dial netlink: %v", err) - } - h := netlink.NewHandler(nlsock) - ec := make(chan os.Error) - go h.Start(ec) - c, err := h.Query(*nlmsg, 1, 4) - if err != nil { - log.Exitf("Couldn't write netlink: %v", err) - } - for i := range( c) { - if i.Header.MessageType() == netlink.NLMSG_DONE { break } - switch i.Header.MessageType() { - case rtnetlink.RTM_NEWLINK: - hdr := &link.Header{} - msg := rtnetlink.NewMessage(hdr, nil) - err = msg.UnmarshalNetlink(i.Body, 4) - if err == nil { - log.Printf("Link[%d] (Family: %v; Type: %v; Flags: %v; Changes: %v)", - hdr.InterfaceIndex(), - hdr.InterfaceFamily(), hdr.InterfaceType(), hdr.Flags(), - hdr.InterfaceChanges()) - for i := range(msg.Attributes){ - log.Printf("Attribute[%d]: %v", i, msg.Attributes[i]) - } - } else { - log.Printf("Unmarshal error: %v", err) - } - default: - log.Printf("Unknown type: %v", i) - } - } +func main() { + nlmsg, err := netlink.NewMessage(rtnetlink.RTM_GETLINK, netlink.NLM_F_DUMP|netlink.NLM_F_REQUEST, &link.Header{}, 4) + if err != nil { + log.Fatalf("Couldn't construct message: %v", err) + } + nlsock, err := netlink.Dial(netlink.NETLINK_ROUTE) + if err != nil { + log.Fatalf("Couldn't dial netlink: %v", err) + } + h := netlink.NewHandler(nlsock) + ec := make(chan error) + go h.Start(ec) + c, err := h.Query(*nlmsg, 1, 4) + if err != nil { + log.Fatalf("Couldn't write netlink: %v", err) + } + for i := range c { + if i.Header.MessageType() == netlink.NLMSG_DONE { + break + } + switch i.Header.MessageType() { + case rtnetlink.RTM_NEWLINK: + hdr := &link.Header{} + msg := rtnetlink.NewMessage(hdr, nil) + err = msg.UnmarshalNetlink(i.Body, 4) + if err == nil { + log.Printf("Link[%d] (Family: %v; Type: %v; Flags: %v; Changes: %v)", + hdr.InterfaceIndex(), + hdr.InterfaceFamily(), hdr.InterfaceType(), hdr.Flags(), + hdr.InterfaceChanges()) + for i := range msg.Attributes { + log.Printf("Attribute[%d]: %v", i, msg.Attributes[i]) + } + } else { + log.Printf("Unmarshal error: %v", err) + } + default: + log.Printf("Unknown type: %v", i) + } + } } diff --git a/tools/get_routes.go b/tools/get_routes.go index fea1341..ca43eae 100644 --- a/tools/get_routes.go +++ b/tools/get_routes.go @@ -10,50 +10,51 @@ package main See LICENSE for details */ -import "os" import "netlink/rtnetlink/route" import "netlink/rtnetlink" import "log" import "netlink" -func main(){ - rtmsg := route.NewHeader(0,0,0,0,0,0,0,0,0) - nlmsg, err := netlink.NewMessage(rtnetlink.RTM_GETROUTE, netlink.NLM_F_DUMP|netlink.NLM_F_REQUEST, rtmsg, 2) - if err != nil { - log.Exitf("Couldn't construct message: %v", err) - } - nlsock, err := netlink.Dial(netlink.NETLINK_ROUTE) - if err != nil { - log.Exitf("Couldn't dial netlink: %v", err) - } - h := netlink.NewHandler(nlsock) - ec := make(chan os.Error) - go h.Start(ec) - c, err := h.Query(*nlmsg, 1, 4) - if err != nil { - log.Exitf("Couldn't write netlink: %v", err) - } - for i := range( c) { - if i.Header.MessageType() == netlink.NLMSG_DONE { break } - switch i.Header.MessageType() { - case rtnetlink.RTM_NEWROUTE: - hdr := &route.Header{} - msg := rtnetlink.NewMessage(hdr, nil) - err = msg.UnmarshalNetlink(i.Body, 4) +func main() { + rtmsg := route.NewHeader(0, 0, 0, 0, 0, 0, 0, 0, 0) + nlmsg, err := netlink.NewMessage(rtnetlink.RTM_GETROUTE, netlink.NLM_F_DUMP|netlink.NLM_F_REQUEST, rtmsg, 2) + if err != nil { + log.Fatalf("Couldn't construct message: %v", err) + } + nlsock, err := netlink.Dial(netlink.NETLINK_ROUTE) + if err != nil { + log.Fatalf("Couldn't dial netlink: %v", err) + } + h := netlink.NewHandler(nlsock) + ec := make(chan error) + go h.Start(ec) + c, err := h.Query(*nlmsg, 1, 4) + if err != nil { + log.Fatalf("Couldn't write netlink: %v", err) + } + for i := range c { + if i.Header.MessageType() == netlink.NLMSG_DONE { + break + } + switch i.Header.MessageType() { + case rtnetlink.RTM_NEWROUTE: + hdr := &route.Header{} + msg := rtnetlink.NewMessage(hdr, nil) + err = msg.UnmarshalNetlink(i.Body, 4) - if err == nil { - log.Printf("Route: %v (%d/%d) TOS: %d; (Table: %v; Origin: %v; Scope: %v; Type: %v; Flags: %v", - hdr.AddressFamily(), hdr.AddressDestLength(), hdr.AddressSourceLength(), - hdr.TOS(), hdr.RoutingTable(), hdr.RouteOrigin(), hdr.AddressScope(), - hdr.RouteType(), hdr.Flags()) - for i := range(msg.Attributes){ - log.Printf("Attribute[%d]: %v", i, msg.Attributes[i]) - } - } else { - log.Printf("Unmarshal error: %v", err) - } - default: - log.Printf("Unknown type: %v", i) - } - } + if err == nil { + log.Printf("Route: %v (%d/%d) TOS: %d; (Table: %v; Origin: %v; Scope: %v; Type: %v; Flags: %v", + hdr.AddressFamily(), hdr.AddressDestLength(), hdr.AddressSourceLength(), + hdr.TOS(), hdr.RoutingTable(), hdr.RouteOrigin(), hdr.AddressScope(), + hdr.RouteType(), hdr.Flags()) + for i := range msg.Attributes { + log.Printf("Attribute[%d]: %v", i, msg.Attributes[i]) + } + } else { + log.Printf("Unmarshal error: %v", err) + } + default: + log.Printf("Unknown type: %v", i) + } + } } diff --git a/tools/ifmanip.go b/tools/ifmanip.go index a16b4f7..9b23922 100644 --- a/tools/ifmanip.go +++ b/tools/ifmanip.go @@ -12,46 +12,49 @@ import "netlink/rtmanip" import "netlink/rtnetlink/link" import "flag" import "log" -import "os" -var doUp = flag.Bool("up",false, "Turn interface up") -var doDown = flag.Bool("down",false, "Turn interface up") +var doUp = flag.Bool("up", false, "Turn interface up") +var doDown = flag.Bool("down", false, "Turn interface up") var ifName = flag.String("ifname", "", "Interface to use") -func main(){ - flag.Parse() - nlsock, err := netlink.Dial(netlink.NETLINK_ROUTE) - if err != nil { - log.Exitf("Couldn't dial netlink: %v", err) - } - h := netlink.NewHandler(nlsock) - ec := make(chan os.Error) - go func(){ - for e := range(ec) { - log.Printf("Netlink error: %v", e) - } - }() - go h.Start(ec) - lf := rtmanip.NewLinkFinder(h) - l, err := lf.GetLinkByName(*ifName) - if err == nil { - if *doDown { - err = l.SetLinkState(^link.IFF_UP, link.IFF_UP) - if err != nil { log.Printf("Couldn't turn down interface: %v", err) } - l.Refresh() - } - if *doUp { - err = l.SetLinkState(link.IFF_UP, link.IFF_UP) - if err != nil { log.Printf("Couldn't turn up interface: %v", err) } - l.Refresh() - } - log.Printf("Link Index: %d", l.LinkIndex()) - log.Printf("Link Name: %s", l.LinkName()) - log.Printf("Link Flags: %s", l.LinkFlags()) - log.Printf("Link MTU: %d", l.LinkMTU()) - log.Printf("Link (l2) Address: %x", l.LinkAddress()) - log.Printf("Link (l2) Broadcast: %x", l.LinkBroadcastAddress()) - } else { - log.Exitf("Couldn't get link: %v", err) - } +func main() { + flag.Parse() + nlsock, err := netlink.Dial(netlink.NETLINK_ROUTE) + if err != nil { + log.Fatalf("Couldn't dial netlink: %v", err) + } + h := netlink.NewHandler(nlsock) + ec := make(chan error) + go func() { + for e := range ec { + log.Printf("Netlink error: %v", e) + } + }() + go h.Start(ec) + lf := rtmanip.NewLinkFinder(h) + l, err := lf.GetLinkByName(*ifName) + if err == nil { + if *doDown { + err = l.SetLinkState(^link.IFF_UP) + if err != nil { + log.Printf("Couldn't turn down interface: %v", err) + } + l.Refresh() + } + if *doUp { + err = l.SetLinkState(link.IFF_UP) + if err != nil { + log.Printf("Couldn't turn up interface: %v", err) + } + l.Refresh() + } + log.Printf("Link Index: %d", l.LinkIndex()) + log.Printf("Link Name: %s", l.LinkName()) + log.Printf("Link Flags: %s", l.LinkFlags()) + log.Printf("Link MTU: %d", l.LinkMTU()) + log.Printf("Link (l2) Address: %x", l.LinkAddress()) + log.Printf("Link (l2) Broadcast: %x", l.LinkBroadcastAddress()) + } else { + log.Fatalf("Couldn't get link: %s, %v", *ifName, err) + } }