Skip to content

Commit a1b4da1

Browse files
tamilmani1989sharmasushant
authored andcommitted
Adding/Remove static arp entry for pod IP in VM (#273)
* add static arp entry in vm (for bridge mode and singletenancy) whenever pod created and remove when its deleted
1 parent e6000f2 commit a1b4da1

File tree

4 files changed

+221
-19
lines changed

4 files changed

+221
-19
lines changed

netlink/link.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ const (
3131
IPVLAN_MODE_MAX
3232
)
3333

34+
const (
35+
ADD = iota
36+
REMOVE
37+
)
38+
3439
// Link represents a network interface.
3540
type Link interface {
3641
Info() *LinkInfo
@@ -384,3 +389,42 @@ func SetLinkHairpin(bridgeName string, on bool) error {
384389

385390
return s.sendAndWaitForAck(req)
386391
}
392+
393+
// AddOrRemoveStaticArp sets/removes static arp entry based on mode
394+
func AddOrRemoveStaticArp(mode int, name string, ipaddr net.IP, mac net.HardwareAddr) error {
395+
s, err := getSocket()
396+
if err != nil {
397+
return err
398+
}
399+
400+
var req *message
401+
state := 0
402+
if mode == ADD {
403+
req = newRequest(unix.RTM_NEWNEIGH, unix.NLM_F_CREATE|unix.NLM_F_REPLACE|unix.NLM_F_ACK)
404+
state = NUD_PERMANENT
405+
} else {
406+
req = newRequest(unix.RTM_DELNEIGH, unix.NLM_F_ACK)
407+
state = NUD_INCOMPLETE
408+
}
409+
410+
iface, err := net.InterfaceByName(name)
411+
if err != nil {
412+
return err
413+
}
414+
415+
msg := neighMsg{
416+
Family: uint8(unix.AF_INET),
417+
Index: uint32(iface.Index),
418+
State: uint16(state),
419+
}
420+
req.addPayload(&msg)
421+
422+
ipData := ipaddr.To4()
423+
dstData := newRtAttr(NDA_DST, ipData)
424+
req.addPayload(dstData)
425+
426+
hwData := newRtAttr(NDA_LLADDR, []byte(mac))
427+
req.addPayload(hwData)
428+
429+
return s.sendAndWaitForAck(req)
430+
}

netlink/netlink_test.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,3 +234,28 @@ func TestSetLinkHairpin(t *testing.T) {
234234
t.Errorf("DeleteLink failed: %+v", err)
235235
}
236236
}
237+
238+
func TestAddRemoveStaticArp(t *testing.T) {
239+
_, err := addDummyInterface(ifName)
240+
if err != nil {
241+
t.Errorf("addDummyInterface failed: %v", err)
242+
}
243+
244+
ip := net.ParseIP("192.168.0.2")
245+
mac, _ := net.ParseMAC("aa:b3:4d:5e:e2:4a")
246+
247+
err = AddOrRemoveStaticArp(ADD, ifName, ip, mac)
248+
if err != nil {
249+
t.Errorf("ret val %v", err)
250+
}
251+
252+
err = AddOrRemoveStaticArp(REMOVE, ifName, ip, mac)
253+
if err != nil {
254+
t.Errorf("ret val %v", err)
255+
}
256+
257+
err = DeleteLink(ifName)
258+
if err != nil {
259+
t.Errorf("DeleteLink failed: %+v", err)
260+
}
261+
}

netlink/protocol.go

Lines changed: 136 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,41 @@ import (
1313
"golang.org/x/sys/unix"
1414
)
1515

16+
const (
17+
NDA_UNSPEC = iota
18+
NDA_DST
19+
NDA_LLADDR
20+
NDA_CACHEINFO
21+
NDA_PROBES
22+
NDA_VLAN
23+
NDA_PORT
24+
NDA_VNI
25+
NDA_IFINDEX
26+
NDA_MAX = NDA_IFINDEX
27+
)
28+
29+
// Neighbor Cache Entry States.
30+
const (
31+
NUD_NONE = 0x00
32+
NUD_INCOMPLETE = 0x01
33+
NUD_REACHABLE = 0x02
34+
NUD_STALE = 0x04
35+
NUD_DELAY = 0x08
36+
NUD_PROBE = 0x10
37+
NUD_FAILED = 0x20
38+
NUD_NOARP = 0x40
39+
NUD_PERMANENT = 0x80
40+
)
41+
42+
// Neighbor Flags
43+
const (
44+
NTF_USE = 0x01
45+
NTF_SELF = 0x02
46+
NTF_MASTER = 0x04
47+
NTF_PROXY = 0x08
48+
NTF_ROUTER = 0x80
49+
)
50+
1651
// Netlink protocol constants that are not already defined in unix package.
1752
const (
1853
IFLA_INFO_KIND = 1
@@ -30,6 +65,40 @@ type serializable interface {
3065
length() int
3166
}
3267

68+
//
69+
// Netlink message
70+
//
71+
72+
// Generic netlink message
73+
type message struct {
74+
unix.NlMsghdr
75+
data []byte
76+
payload []serializable
77+
}
78+
79+
// Generic netlink message attribute
80+
type attribute struct {
81+
unix.NlAttr
82+
value []byte
83+
children []serializable
84+
}
85+
86+
// Neighbor entry message strutcure
87+
type neighMsg struct {
88+
Family uint8
89+
Index uint32
90+
State uint16
91+
Flags uint8
92+
Type uint8
93+
}
94+
95+
// rta attribute structure
96+
type rtAttr struct {
97+
unix.RtAttr
98+
Data []byte
99+
children []serializable
100+
}
101+
33102
// Byte encoder
34103
var encoder binary.ByteOrder
35104

@@ -43,17 +112,6 @@ func initEncoder() {
43112
}
44113
}
45114

46-
//
47-
// Netlink message
48-
//
49-
50-
// Generic netlink message
51-
type message struct {
52-
unix.NlMsghdr
53-
data []byte
54-
payload []serializable
55-
}
56-
57115
// Creates a new netlink message.
58116
func newMessage(msgType int, flags int) *message {
59117
return &message{
@@ -127,14 +185,6 @@ func (msg *message) getAttributes(body serializable) []*attribute {
127185
//
128186
// Netlink message attribute
129187
//
130-
131-
// Generic netlink message attribute
132-
type attribute struct {
133-
unix.NlAttr
134-
value []byte
135-
children []serializable
136-
}
137-
138188
// Creates a new attribute.
139189
func newAttribute(attrType int, value []byte) *attribute {
140190
return &attribute{
@@ -339,3 +389,70 @@ func (rt *rtMsg) serialize() []byte {
339389
func (rt *rtMsg) length() int {
340390
return unix.SizeofRtMsg
341391
}
392+
393+
// serialize neighbor message
394+
func (msg *neighMsg) serialize() []byte {
395+
return (*(*[unsafe.Sizeof(*msg)]byte)(unsafe.Pointer(msg)))[:]
396+
}
397+
398+
func (msg *neighMsg) length() int {
399+
return int(unsafe.Sizeof(*msg))
400+
}
401+
402+
// creates new rta attr message
403+
func newRtAttr(attrType int, data []byte) *rtAttr {
404+
return &rtAttr{
405+
RtAttr: unix.RtAttr{
406+
Type: uint16(attrType),
407+
},
408+
children: []serializable{},
409+
Data: data,
410+
}
411+
}
412+
413+
// align rta attributes
414+
func rtaAlignOf(attrlen int) int {
415+
return (attrlen + unix.RTA_ALIGNTO - 1) & ^(unix.RTA_ALIGNTO - 1)
416+
}
417+
418+
// serialize rta message
419+
func (rta *rtAttr) serialize() []byte {
420+
length := rta.length()
421+
buf := make([]byte, rtaAlignOf(length))
422+
423+
next := 4
424+
if rta.Data != nil {
425+
copy(buf[next:], rta.Data)
426+
next += rtaAlignOf(len(rta.Data))
427+
}
428+
if len(rta.children) > 0 {
429+
for _, child := range rta.children {
430+
childBuf := child.serialize()
431+
copy(buf[next:], childBuf)
432+
next += rtaAlignOf(len(childBuf))
433+
}
434+
}
435+
436+
if l := uint16(length); l != 0 {
437+
encoder.PutUint16(buf[0:2], l)
438+
}
439+
encoder.PutUint16(buf[2:4], rta.Type)
440+
return buf
441+
}
442+
443+
func (rta *rtAttr) length() int {
444+
if len(rta.children) == 0 {
445+
return (unix.SizeofRtAttr + len(rta.Data))
446+
}
447+
448+
l := 0
449+
for _, child := range rta.children {
450+
l += rtaAlignOf(child.length())
451+
}
452+
l += unix.SizeofRtAttr
453+
return rtaAlignOf(l + len(rta.Data))
454+
}
455+
456+
func (rta *rtAttr) addChild(attr serializable) {
457+
rta.children = append(rta.children, attr)
458+
}

network/bridge_endpointclient_linux.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,14 @@ func (client *LinuxBridgeEndpointClient) AddEndpointRules(epInfo *EndpointInfo)
7272
if err := ebtables.SetDnatForIPAddress(client.hostPrimaryIfName, ipAddr.IP, client.containerMac, ebtables.Append); err != nil {
7373
return err
7474
}
75+
76+
if client.mode != opModeTunnel {
77+
log.Printf("[net] Adding static arp for IP address %v and MAC %v in VM", ipAddr.String(), client.containerMac.String())
78+
netlink.AddOrRemoveStaticArp(netlink.ADD, client.bridgeName, ipAddr.IP, client.containerMac)
79+
if err != nil {
80+
log.Printf("Failed setting arp in vm: %v", err)
81+
}
82+
}
7583
}
7684

7785
log.Printf("[net] Setting hairpin for hostveth %v", client.hostVethName)
@@ -99,6 +107,14 @@ func (client *LinuxBridgeEndpointClient) DeleteEndpointRules(ep *endpoint) {
99107
if err != nil {
100108
log.Printf("[net] Failed to delete MAC DNAT rule for IP address %v: %v.", ipAddr.String(), err)
101109
}
110+
111+
if client.mode != opModeTunnel {
112+
log.Printf("[net] Removing static arp for IP address %v and MAC %v from VM", ipAddr.String(), ep.MacAddress.String())
113+
netlink.AddOrRemoveStaticArp(netlink.REMOVE, client.bridgeName, ipAddr.IP, ep.MacAddress)
114+
if err != nil {
115+
log.Printf("Failed removing arp from vm: %v", err)
116+
}
117+
}
102118
}
103119
}
104120

0 commit comments

Comments
 (0)