我正在使用 RYU 控制器和 Mininet 模拟器构建网络。当控制器收到 packet_in 事件时,它会在存储的地址中查找 IP 地址。如果未找到,则数据包会通过网络泛洪。然而,这是低效的,因为如果目标主机不在网络中,它可能会徒劳地淹没网络。
我尝试过的一个解决方案是让主机在网络开始学习其 IP 地址时发送虚拟数据包。但我想知道是否有更专业或推荐的方法来避免不必要的数据包淹没网络。对于这种情况有什么建议或最佳做法吗?
在 packet_in 事件中控制器接收到数据包之前,如果发送方不知道目标的 MAC 地址,则会收到 ARP 请求。控制器应该在设置数据包本身的流之前做出响应。场景如下:
记住不要尽可能长时间地淹没网络。
示例代码:
@set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
def _packet_in_handler(self, ev):
pkt = packet.Packet(ev.msg.data)
eth = pkt.get_protocol(ethernet.ethernet)
# avoid broadcast from LLDP
if eth.ethertype == 35020:
return
# drop the IPV6 Packets if not using IPV6
if pkt.get_protocol(ipv6.ipv6):
match = ev.msg.datapath.ofproto_parser.OFPMatch(eth_type=eth.ethertype)
actions = []
self.add_flow(ev.msg.datapath, 1, match, actions)
return
arp_pkt = pkt.get_protocol(arp.arp)
if arp_pkt:
# ARP packet is received
# Store the sender host information
src_ip = arp_pkt.src_ip
src_mac = arp_pkt.src_mac
if src_ip not in self.arp_table:
self.arp_table[src_ip] = src_mac
dst_ip = arp_pkt.dst_ip
if arp_pkt.opcode == arp.ARP_REQUEST:
if dst_ip in hosts_by_ip:
# If ARP request and destination MAC is known, send ARP reply
print("ARP destination is in hosts, sending ARP reply")
dst_mac = self.arp_table[dst_ip]
self.send_arp_reply(ev.msg.datapath,
dst_mac, src_mac, dst_ip, src_ip, ev.msg.match['in_port'])
else:
# If ARP request and destination MAC is not known, send ARP request to all hosts
print("ARP destination is not in hosts, sending ARP request")
for dp in self.datapaths.values():
self.send_arp_request(dp, src_mac, src_ip, dst_ip)
else:
print("ARP reply received from ", src_ip)
# No need to do anything as we already stored the host IP, we wait for the requester to send another ARP request
else:
# IPv4 packet received because no flow was found in the switch flow table
# TODO: set the flow (in the switch) here
def send_arp_reply(self, datapath, src_mac, dst_mac, src_ip, dst_ip, in_port):
self.send_arp(datapath, arp.ARP_REPLY, src_mac,
src_ip, dst_mac, dst_ip, in_port)
def send_arp_request(self, datapath, src_mac, src_ip, dst_ip):
self.send_arp(datapath, arp.ARP_REQUEST, src_mac,
src_ip, None, dst_ip, None)
def send_arp(self, datapath, opcode, src_mac, src_ip, dst_mac, dst_ip, in_port):
eth_dst_mac = dst_mac
arp_dst_mac = dst_mac
actions = [datapath.ofproto_parser.OFPActionOutput(in_port)]
if opcode == arp.ARP_REQUEST:
eth_dst_mac = 'ff:ff:ff:ff:ff:ff'
arp_dst_mac = '00:00:00:00:00:00'
actions = [datapath.ofproto_parser.OFPActionOutput(
datapath.ofproto.OFPP_FLOOD)]
# Create Ethernet header
eth = ethernet.ethernet(
dst=eth_dst_mac,
src=src_mac,
ethertype=packet.ethernet.ether.ETH_TYPE_ARP
)
# Create ARP header
arp_header = arp.arp(
opcode=opcode,
src_mac=src_mac,
src_ip=src_ip,
dst_mac=arp_dst_mac,
dst_ip=dst_ip
)
# Create packet and send it
pkt = packet.Packet()
pkt.add_protocol(eth)
pkt.add_protocol(arp_header)
pkt.serialize()
datapath.send_packet_out(
buffer_id=datapath.ofproto.OFP_NO_BUFFER,
in_port=datapath.ofproto.OFPP_CONTROLLER,
actions=actions,
data=pkt.data
)