From b56ae9dbfbaaaff338ff27004ca679a6555d0af7 Mon Sep 17 00:00:00 2001 From: MaMe82 Date: Thu, 6 Sep 2018 23:07:09 +0200 Subject: [PATCH] NETLINK: added NetworkLinkGetStateUp method to test link up/down --- netlink/netlink_linux.go | 106 +++++++++++++++++++++++++++++++++------ 1 file changed, 90 insertions(+), 16 deletions(-) diff --git a/netlink/netlink_linux.go b/netlink/netlink_linux.go index f88516a..72f856e 100644 --- a/netlink/netlink_linux.go +++ b/netlink/netlink_linux.go @@ -32,13 +32,12 @@ const ( ) const ( - MACVLAN_MODE_PRIVATE = 1 << iota + MACVLAN_MODE_PRIVATE = 1 << iota MACVLAN_MODE_VEPA MACVLAN_MODE_BRIDGE MACVLAN_MODE_PASSTHRU ) - const ( // See linux/if_arp.h. // Note that Linux doesn't support IPv4 over IPv6 tunneling. @@ -499,6 +498,78 @@ func NetworkLinkDel(name string) error { return s.HandleAck(wb.Seq) } +// see https://www.infradead.org/~tgr/libnl/doc/route.html + +// Returns an array of IPNet for all the currently routed subnets on ipv4 +// This is similar to the first column of "ip route" output +func NetworkLinkGetStateUp(iface *net.Interface) (err error, res bool) { + //fmt.Println("Needed if idx", iface.Index) + + s, err := getNetlinkSocket() + if err != nil { + return err, false + } + defer s.Close() + + wb := newNetlinkRequest(syscall.RTM_GETLINK, syscall.NLM_F_DUMP) + + msg := newIfInfomsg(syscall.AF_UNSPEC) + msg.Index = int32(iface.Index) + + wb.AddData(msg) + + if err := s.Send(wb); err != nil { + return err, false + } + + // retrieve PID + pid, err := s.GetPid() + if err != nil { + return err, false + } + +outer: +// Receive loop + for { + msgs, err := s.Receive() + if err != nil { + return err, false + } + // loop over incoming NL messages + for _, m := range msgs { + // fmt.Printf("Message %+v\n", m) + + // check if seq number and receiver PID are correct, abort receive loop on Type == NLMSG_DONE (translated to EOF) + if err := s.CheckMessage(m, wb.Seq, pid); err != nil { + if err == io.EOF { + break outer // abort receive loop if multipart messages reached eof + } + return err, false + } + + // the result we want to fetch + if m.Header.Type != syscall.RTM_NEWLINK { + continue + } + + //Cast first part to IfInfoMsg + msg := (*IfInfomsg)(unsafe.Pointer(&m.Data[0:syscall.SizeofIfInfomsg][0])) + + // Ignore message for different interface + if msg.Index != int32(iface.Index) { + continue + } + + if_up := msg.Flags&syscall.IFF_UP != 0 + //fmt.Printf("Message: %+v\n", msg) + //fmt.Printf("Flag IFF_UP: %+v\n", if_up) + return nil, if_up + } + } + + return errors.New("Couldn't retreive link state"), false +} + // Bring up a particular network interface. // This is identical to running: ip link set dev $name up func NetworkLinkUp(iface *net.Interface) error { @@ -648,7 +719,6 @@ func NetworkSetMTU(iface *net.Interface, mtu int) error { return s.HandleAck(wb.Seq) } - // Set link queue length // This is identical to running: ip link set dev $name txqueuelen $QLEN func NetworkSetTxQueueLen(iface *net.Interface, txQueueLen int) error { @@ -997,7 +1067,6 @@ func networkLinkIpAction4(action, flags int, ifa IfAddr, ifa_broadcast IfAddr) e msg.Prefixlen = uint8(prefixLen) wb.AddData(msg) - ipData := ifa.IP.To4() localData := newRtAttr(syscall.IFA_LOCAL, ipData) @@ -1006,7 +1075,6 @@ func networkLinkIpAction4(action, flags int, ifa IfAddr, ifa_broadcast IfAddr) e addrData := newRtAttr(syscall.IFA_ADDRESS, ipData) wb.AddData(addrData) - ipBcData := ifa_broadcast.IP.To4() brAddrData := newRtAttr(syscall.IFA_BROADCAST, ipBcData) wb.AddData(brAddrData) @@ -1028,7 +1096,7 @@ func NetworkLinkDelIp(iface *net.Interface, ip net.IP, ipNet *net.IPNet) error { ) } -func IpBroadcast4(n *net.IPNet) (net.IP, error) { +func IpBroadcast4(n *net.IPNet) (net.IP, error) { ipv4 := n.IP.To4() if ipv4 == nil { return nil, errors.New("No IPv4 net") @@ -1038,12 +1106,12 @@ func IpBroadcast4(n *net.IPNet) (net.IP, error) { maskv4 = maskv4[12:] } - res := net.IPv4(0xff,0xff,0xff,0xff).To4() - for i:=0; i