-
Notifications
You must be signed in to change notification settings - Fork 10
/
host.go
136 lines (120 loc) · 3.86 KB
/
host.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
// SPDX-FileCopyrightText: 2022-present Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0
package simulator
import (
"github.com/google/gopacket/layers"
simapi "github.com/onosproject/onos-api/go/onos/fabricsim"
"github.com/onosproject/onos-net-lib/pkg/p4utils"
"github.com/onosproject/onos-net-lib/pkg/packet"
"math/rand"
"sync"
"time"
)
// HostSimulator simulates a single host
type HostSimulator struct {
Host *simapi.Host
simulation *Simulation
lock sync.RWMutex
done chan string
}
// NewHostSimulator initializes a new device simulator
func NewHostSimulator(host *simapi.Host, simulation *Simulation) *HostSimulator {
log.Infof("Host %s: Creating simulator", host.ID)
return &HostSimulator{
Host: host,
simulation: simulation,
done: make(chan string),
}
}
// Start starts background host simulation activities, e.g. emitting ARP and DHCP packets
func (hs *HostSimulator) Start() {
hs.lock.Lock()
defer hs.lock.Unlock()
go hs.emitARPRequests()
}
// Stop stops any background host simulation activities
func (hs *HostSimulator) Stop() {
hs.done <- "stop"
}
// SendARPRequest simulates emission of an ARP request as a packet-in on all the hosts' interfaces
func (hs *HostSimulator) SendARPRequest(another *simapi.NetworkInterface) {
for _, nic := range hs.Host.Interfaces {
if err := hs.EmitARPRequests(nic, []string{another.IpAddress}); err != nil {
log.Warnf("Host %s: Unable to emit ARP for %s: %v", hs.Host.ID, another.IpAddress, err)
}
}
}
// SendARPResponse simulates emission of an ARP response as a packet-in on all the hosts' interfaces
func (hs *HostSimulator) SendARPResponse(another *simapi.Host) {
// TODO: implement this when needed
}
const (
arpMinDelay = 30
arpVardelay = 30
)
// Periodically emit ARP requests for other hosts' IP addresses
func (hs *HostSimulator) emitARPRequests() {
for {
select {
case <-time.After(time.Duration(arpMinDelay+rand.Intn(arpVardelay)) * time.Second):
hs.emitRandomARPRequest()
case <-hs.done:
return
}
}
}
// Picks a random host (other than us) and emits an ARP query for it
func (hs *HostSimulator) emitRandomARPRequest() {
if another := hs.simulation.GetRandomHostSimulator(hs); another != nil {
hs.SendARPRequest(another.GetRandomNetworkInterface())
}
}
// GetRandomNetworkInterface returns randomly chosen network interface for the host
func (hs *HostSimulator) GetRandomNetworkInterface() *simapi.NetworkInterface {
hs.lock.RLock()
defer hs.lock.RUnlock()
ri := rand.Intn(len(hs.Host.Interfaces))
i := 0
for _, nic := range hs.Host.Interfaces {
if i == ri {
return nic
}
i++
}
return nil
}
// EmitARPRequests triggers the specified host NIC to send ARP requests for a set of IP addresses
func (hs *HostSimulator) EmitARPRequests(nic *simapi.NetworkInterface, dstIPs []string) error {
for _, ip := range dstIPs {
arp, err := packet.ARPRequestPacket(packet.IP(ip), packet.MAC(nic.MacAddress), packet.IP(nic.IpAddress))
if err != nil {
log.Warnf("Host %s: Unable to serialize ARP request: %+v", hs.Host.ID, err)
continue
}
deviceSim, err := hs.simulation.GetDeviceSimulatorForPort(nic.ID)
if err != nil {
log.Warnf("Host %s: Unable to find device simulator: %+v", hs.Host.ID, err)
continue
}
if deviceSim.Ports[nic.ID].Enabled {
if roleAgentID, ok := deviceSim.HasPuntRuleForEthType(layers.EthernetTypeARP); ok {
deviceSim.SendPacketIn(arp, &p4utils.PacketInMetadata{
IngressPort: deviceSim.Ports[nic.ID].InternalNumber,
RoleAgentID: roleAgentID,
})
}
}
}
return nil
}
// GetNetworkInterfaceByMac returns the network interface associated with the specified MAC address on this host
func (hs *HostSimulator) GetNetworkInterfaceByMac(mac string) *simapi.NetworkInterface {
for _, nic := range hs.Host.Interfaces {
if nic.MacAddress == mac {
return nic
}
}
return nil
}
// TODO: Additional simulation logic goes here