Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PR - Added an embedded ip resolver #550

Merged
merged 2 commits into from
Feb 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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
}
}