Skip to content

Commit

Permalink
Merge pull request loxilb-io#550 from TrekkieCoder/main
Browse files Browse the repository at this point in the history
PR - Added an embedded ip resolver
  • Loading branch information
UltraInstinct14 authored Feb 26, 2024
2 parents a09a1be + eda0fdb commit a92bb7f
Show file tree
Hide file tree
Showing 5 changed files with 176 additions and 2 deletions.
6 changes: 6 additions & 0 deletions loxinet/dpbroker.go
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,12 @@ func (ct *DpCtInfo) Key() string {
return str
}

// KeyState - outputs a key string for given DpCtInfo pointer with state info
func (ct *DpCtInfo) KeyState() string {
str := fmt.Sprintf("%s%s%d%d%s-%s", ct.DIP.String(), ct.SIP.String(), ct.Dport, ct.Sport, ct.Proto, ct.CState)
return str
}

// String - stringify the given DpCtInfo
func (ct *DpCtInfo) String() string {
str := fmt.Sprintf("%s:%d->%s:%d (%s), ", ct.SIP.String(), ct.Sport, ct.DIP.String(), ct.Dport, ct.Proto)
Expand Down
8 changes: 8 additions & 0 deletions loxinet/dpebpf_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ package loxinet
int bpf_map_get_next_key(int fd, const void *key, void *next_key);
int bpf_map_lookup_elem(int fd, const void *key, void *value);
extern void goMapNotiHandler(struct ll_dp_map_notif *);
extern void goLinuxArpResolver(unsigned int);
#cgo CFLAGS: -I./../loxilb-ebpf/libbpf/src/ -I./../loxilb-ebpf/common
#cgo LDFLAGS: -L. -L/lib64 -L./../loxilb-ebpf/kernel -L./../loxilb-ebpf/libbpf/src/build/usr/lib64/ -Wl,-rpath=/lib64/ -lloxilbdp -lbpf -lelf -lz
*/
Expand Down Expand Up @@ -1034,6 +1035,7 @@ func (e *DpEbpfH) DpStat(w *StatDpWorkQ) int {
switch {
case w.Name == MapNameNat4:
tbl = append(tbl, int(C.LL_DP_NAT_STATS_MAP))
sync = 1
case w.Name == MapNameBD:
tbl = append(tbl, int(C.LL_DP_BD_STATS_MAP), int(C.LL_DP_TX_BD_STATS_MAP))
case w.Name == MapNameRxBD:
Expand Down Expand Up @@ -2059,3 +2061,9 @@ func (e *DpEbpfH) DpRelLock() {
func (e *DpEbpfH) DpTableGC() {
e.trigGC <- true
}

//export goLinuxArpResolver
func goLinuxArpResolver(dIP C.uint) {
goDest := uint32(dIP)
ArpResolver(goDest)
}
10 changes: 10 additions & 0 deletions loxinet/rules.go
Original file line number Diff line number Diff line change
Expand Up @@ -746,6 +746,8 @@ func (R *RuleH) GetNatLbRule() ([]cmn.LbRuleMod, error) {
ret.Serv.Proto = "icmp"
} else if data.tuples.l4Prot.val == 132 {
ret.Serv.Proto = "sctp"
} else if data.tuples.l4Prot.val == 0 {
ret.Serv.Proto = "none"
} else {
return []cmn.LbRuleMod{}, errors.New("malformed service proto")
}
Expand Down Expand Up @@ -907,6 +909,8 @@ func (R *RuleH) GetNatLbRuleByServArgs(serv cmn.LbServiceArg) *ruleEnt {
ipProto = 1
} else if serv.Proto == "sctp" {
ipProto = 132
} else if serv.Proto == "none" {
ipProto = 0
} else {
return nil
}
Expand Down Expand Up @@ -1252,6 +1256,8 @@ func (R *RuleH) AddNatLbRule(serv cmn.LbServiceArg, servSecIPs []cmn.LbSecIPArg,
ipProto = 1
} else if serv.Proto == "sctp" {
ipProto = 132
} else if serv.Proto == "none" {
ipProto = 0
} else {
return RuleUnknownServiceErr, errors.New("malformed-proto error")
}
Expand Down Expand Up @@ -1483,6 +1489,8 @@ func (R *RuleH) DeleteNatLbRule(serv cmn.LbServiceArg) (int, error) {
ipProto = 1
} else if serv.Proto == "sctp" {
ipProto = 132
} else if serv.Proto == "none" {
ipProto = 0
} else {
return RuleUnknownServiceErr, errors.New("malformed-proto error")
}
Expand Down Expand Up @@ -2213,6 +2221,8 @@ func (R *RuleH) RuleDestructAll() {
lbs.Proto = "udp"
} else if r.tuples.l4Prot.val == 132 {
lbs.Proto = "sctp"
} else if r.tuples.l4Prot.val == 0 {
lbs.Proto = "none"
} else {
continue
}
Expand Down
152 changes: 151 additions & 1 deletion loxinet/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import (
"encoding/binary"
"errors"
"fmt"
tk "github.com/loxilb-io/loxilib"
"io/ioutil"
"net"
"net/http"
Expand All @@ -34,6 +33,10 @@ import (
"strings"
"syscall"
"time"
"unsafe"

tk "github.com/loxilb-io/loxilib"
nlp "github.com/vishvananda/netlink"
)

// IterIntf - interface implementation to iterate various loxinet
Expand Down Expand Up @@ -341,3 +344,150 @@ func FormatTimedelta(t time.Time) string {
}
return fmt.Sprintf("%dd ", days) + fmt.Sprintf("%02d:%02d:%02d", hours, mins, secs)
}

// Ntohll - Network to host byte-order long long
func Ntohll(i uint64) uint64 {
return binary.BigEndian.Uint64((*(*[8]byte)(unsafe.Pointer(&i)))[:])
}

// GetIfaceIpAddr - Get interface IP address
func GetIfaceIpAddr(ifName string) (addr net.IP, err error) {
var (
ief *net.Interface
addrs []net.Addr
ipAddr net.IP
)
if ief, err = net.InterfaceByName(ifName); err != nil {
return
}
if addrs, err = ief.Addrs(); err != nil {
return
}
for _, addr := range addrs {
if ipAddr = addr.(*net.IPNet).IP.To4(); ipAddr != nil {
break
}
}
if ipAddr == nil {
return nil, errors.New(fmt.Sprintf("%s - no ipv4 address\n", ifName))
}
return ipAddr, nil
}

// SendArpReq - sends a arp request given the DIP, SIP and interface name
func SendArpReq(AdvIP net.IP, ifName string) (int, error) {
zeroAddr := []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}

srcIP, err := GetIfaceIpAddr(ifName)
if err != nil {
return -1, errors.New(fmt.Sprintf("%s", err))
}
fd, err := syscall.Socket(syscall.AF_PACKET, syscall.SOCK_DGRAM, int(tk.Htons(syscall.ETH_P_ARP)))
if err != nil {
return -1, errors.New("af-packet-err")
}
defer syscall.Close(fd)

if err := syscall.BindToDevice(fd, ifName); err != nil {
return -1, errors.New("bind-err")
}

ifi, err := net.InterfaceByName(ifName)
if err != nil {
return -1, errors.New("intf-err")
}

ll := syscall.SockaddrLinklayer{
Protocol: tk.Htons(syscall.ETH_P_ARP),
Ifindex: ifi.Index,
Pkttype: 0, // syscall.PACKET_HOST
Hatype: 1,
Halen: 6,
}

for i := 0; i < 8; i++ {
ll.Addr[i] = 0xff
}

buf := new(bytes.Buffer)

var sb = make([]byte, 2)
binary.BigEndian.PutUint16(sb, 1) // HwType = 1
buf.Write(sb)

binary.BigEndian.PutUint16(sb, 0x0800) // protoType
buf.Write(sb)

buf.Write([]byte{6}) // hwAddrLen
buf.Write([]byte{4}) // protoAddrLen

binary.BigEndian.PutUint16(sb, 0x1) // OpCode
buf.Write(sb)

buf.Write(ifi.HardwareAddr) // senderHwAddr
buf.Write(srcIP.To4()) // senderProtoAddr

buf.Write(zeroAddr) // targetHwAddr
buf.Write(AdvIP.To4()) // targetProtoAddr

if err := syscall.Bind(fd, &ll); err != nil {
return -1, errors.New("bind-err")
}
if err := syscall.Sendto(fd, buf.Bytes(), 0, &ll); err != nil {
return -1, errors.New("send-err")
}

return 0, nil
}

// ArpReqWithCtx - sends a arp req given the DIP, SIP and interface name
func ArpReqWithCtx(ctx context.Context, rCh chan<- int, AdvIP net.IP, ifName string) (int, error) {
for {
select {
case <-ctx.Done():
return -1, ctx.Err()
default:
ret, _ := SendArpReq(AdvIP, ifName)
rCh <- ret
return 0, nil
}
}
}

func ArpResolver(dIP uint32) {
var gw net.IP
var ifName string
dest := tk.NltoIP(dIP)

routes, err := nlp.RouteGet(dest)
if err != nil {
return
}

for _, r := range routes {
if r.Gw == nil {
gw = r.Dst.IP
} else {
gw = r.Gw
}
if gw == nil {
continue
}
link, err := nlp.LinkByIndex(r.LinkIndex)
if err != nil {
return
}
ifName = link.Attrs().Name
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
rCh := make(chan int)
go ArpReqWithCtx(ctx, rCh, gw, ifName)
select {
case <-rCh:
break
case <-ctx.Done():
tk.LogIt(tk.LogInfo, "%s - iface %s : ARP timeout\n", gw.String(), ifName)
}
return
}
}

0 comments on commit a92bb7f

Please sign in to comment.