I'm building a network using the RYU controller and Mininet simulator. When the controller receives a packet_in event, it looks up the IP address in the stored addresses. If it's not found, the packet is flooded through the network. However, this is inefficient because it could flood the network in vain if the target host isn't in the network.
One solution I've tried is having the hosts send dummy packets when the network starts to learn their IP addresses. But I'm wondering if there's a more professional or recommended approach to avoid flooding the network with unnecessary packets. Any suggestions or best practices for this scenario?
Before the packet itself is received at the controller in the packet_in event, an ARP request is received if the sender doesn't know the MAC address of the destination. The controller should respond before setting the flow of the packet itself. The scenario happens as follows:
Remember not to flood the network as long as you can.
Example code:
@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
)