Skip to content

Commit

Permalink
Gratuitous ARP On StartUP
Browse files Browse the repository at this point in the history
  • Loading branch information
KusakabeShi committed Aug 3, 2021
1 parent 721c146 commit 8287d95
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 10 deletions.
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ Create a json file at `/etc/wggo-vpp/if.home.json` with following content:
"IPv6NdpNeighAdvRanges": [
"fd28:cb8f:4c92::33/128","fe80::42:1817:1/128"
],
"GratuitousARPOnStartUP": false,
"IPv4ArpLearningRanges": [ ],
"IPv6NdpLearningRanges": [ ],
"VppBridgeID": 4242
Expand All @@ -107,8 +108,9 @@ Create a json file at `/etc/wggo-vpp/if.home.json` with following content:
5. IPv6NdpNeighAdvRanges: Similar to `IPv4ArpResponseRanges`, but it replies Neighbor Advertisement if a Neighbor Solicitation received.
1. If you add link-local address in this section, mask length must be `128` because VPP doesn't support ipv6 link-local with mask other than `/128`.
2. You can add multiple `/128` link-local address in this section if you need.
6. IPv6NdpLearningRanges(Optional): Same as `IPv4ArpLearningRanges`, but it's IPv6 version.
7. VppBridgeID: VppBridge ID defined in previous section. We need to use this value in next section.
6. GratuitousARPOnStartUP: Send `Gratuitous ARP` and `Unsolicited Neighbor Advertisement` through all `IPv4ArpResponseRanges` and `IPv6NdpNeighAdvRanges` at `wggo-vpp` start up.
7. IPv6NdpLearningRanges(Optional): Same as `IPv4ArpLearningRanges`, but it's IPv6 version.
8. VppBridgeID: VppBridge ID defined in previous section. We need to use this value in next section.

### Gateway config

Expand All @@ -129,12 +131,12 @@ Create a json file at `/etc/wggo-vpp/gw.4242.json` with following content:
"VppBridgeLoop_SwIfName":"loop42",
"VppBridgeLoop_SwIfIndex":1,
"VppBridgeLoop_InstallNeighbor":{
"IPv4":false,
"IPv4":true,
"IPv6":false,
"IPv6 link-local":false
},
"VppBridgeLoop_InstallNeighbor_Flag":{
"static":true,
"static":false,
"no-fib-entry":false
},
"VppBridgeLoop_InstallRoutes":{
Expand Down
67 changes: 61 additions & 6 deletions tun/tun_linux_vpp.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,11 +110,12 @@ type InterfaceConfig struct {
Macaddr string //Overwrite gwConfig.WgIfMacaddrPrefix
vppIfMacAddr string

IPv4ArpResponseRanges []string
IPv4ArpLearningRanges []string
IPv6NdpNeighAdvRanges []string
IPv6NdpLearningRanges []string
VppBridgeID uint32
IPv4ArpResponseRanges []string
IPv6NdpNeighAdvRanges []string
GratuitousARPOnStartUP bool
IPv6NdpLearningRanges []string
IPv4ArpLearningRanges []string
VppBridgeID uint32
}

type NativeTun struct {
Expand Down Expand Up @@ -568,6 +569,14 @@ func (tun *NativeTun) sendARPReply(queueID uint8, l2srcMac []byte, l2dstMac []by
if gwConfig.VppBridgeLoop_InstallNeighbor.IPv4 == false {
return err //Skip
}
if bytes.Equal(l2dstMac, tun.gwMacAddr) {
// Pass check
} else if bytes.Equal(l2dstMac, net.HardwareAddr{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}) {
// Pass check
} else {
//Install via api only if this ARP reply to the gateway/broadcast/multicast
return nil //Otherwise return
}
switch gwConfig.VppBridgeLoop_InstallMethod {
case "api":
{
Expand Down Expand Up @@ -725,7 +734,14 @@ func (tun *NativeTun) sendNDNA(queueID uint8, l2srcMac []byte, l2dstMac []byte,
var response = buf.Bytes()
tun.DumpPacket("#############Packet Sent############", response)
_, err = tun.memif.TxBurst(queueID, []libmemif.RawPacketData{response})

if bytes.Equal(l2dstMac, tun.gwMacAddr) {
// Pass check
} else if bytes.Equal(l2dstMac[:2], []byte{0x33, 0x33}) {
// Pass check
} else {
//Install via api only if this ARP reply to the gateway/broadcast/multicast
return nil //Otherwise return
}
if gwConfig.VppBridgeLoop_InstallNeighbor.IPv6LL && isLinkLocal(natrg) {
// install neighbor
} else if gwConfig.VppBridgeLoop_InstallNeighbor.IPv6 && !isLinkLocal(natrg) {
Expand Down Expand Up @@ -1488,9 +1504,48 @@ func CreateTUN(name string, mtu int) (Device, error) {
//return nil, err
//VPP can learn l2fib later if this command failed
}
selfIfMacAddrs := selfIfMacAddr[:]
boardcastMac := []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
multicastMac := []byte{0x33, 0x33, 0x00, 0x00, 0x00, 0x01}

if ifConfig.GratuitousARPOnStartUP {
for _, ipv4Net := range tun.selfIPv4ARPRspRanges {
mask := binary.BigEndian.Uint32(ipv4Net.Mask)
start := binary.BigEndian.Uint32(ipv4Net.IP)
finish := (start & mask) | (mask ^ 0xffffffff)
// loop through addresses as uint32
for i := start; i <= finish; i++ {
// convert back to net.IP
ip := make(net.IP, 4)
binary.BigEndian.PutUint32(ip, i)
// Send Gratuitous ARP
tun.logger.Debugln("Send Gratuitous ARP: " + ip.String())
tun.sendARPReply(0, selfIfMacAddrs, boardcastMac, selfIfMacAddrs, ip.To4(), boardcastMac, ip.To4())
}
}
all_nodes_ipv6 := net.ParseIP("ff02::1")
for _, ipv6Net := range tun.selfIPv6NDPRspRanges {
start := net.IP(make([]byte, 16))
copy(start, ipv6Net.IP)
for theIP := start; ipv6Net.Contains(theIP); incIP(theIP) {
tun.logger.Debugln("Send unsolicited neighbour advertisement: " + theIP.String())
tun.sendNDNA(0, selfIfMacAddrs, multicastMac, theIP, all_nodes_ipv6, theIP, selfIfMacAddrs)
}

}
}
return tun, nil
}

func incIP(ip net.IP) {
for j := len(ip) - 1; j >= 0; j-- {
ip[j]++
if ip[j] > 0 {
break
}
}
}

// OnConnect is called when a memif connection gets established.
func OnConnect(memif *libmemif.Memif) (err error) {
details, err := memif.GetDetails()
Expand Down

0 comments on commit 8287d95

Please sign in to comment.