问题描述
我试图在使用 Ryu 控制器的 SDN 环境中仅丢弃超过规定阈值的 TCP 数据包。为什么所有超过丢弃的数据包?例如ICMP。
def protect_our_network(self,datapath,in_port,src_ip,dst_ip):
if not src_ip in self.packets_by_ip:
self.packets_by_ip[src_ip] = 0
self.packets_by_ip[src_ip] += 1
if in_port != 1:
if self.packets_by_ip[src_ip] == 40:
self.launch_countermeasures(datapath,src_ip)
return True
if self.packets_by_ip[src_ip] > 40:
# Just some lingering packets that got through before
# our block rule became effective.
return True
if in_port == 1 and self.packets_by_ip.get(dst_ip,0) > 40:
return True
return False
def launch_countermeasures(self,src_ip):
match = parser.OFPMatch(
eth_type = ether_types.ETH_TYPE_IP,ipv4_src = src_ip,ip_proto=6
)
self.set_flow(datapath,match,[],priority = 2)
warn = " WARNING! Traffic limit exceeded for IP {:s}!".format(src_ip)
warn += " Dropping packets!"
print(warn)
解决方法
当您在 launch_countermeasures()
中安装该流规则时,所有具有给定 src_ip
的 tcp 数据包都会在交换机上丢弃。但是,所有具有相同 src_ip
的非 tcp 数据包仍将发送到控制器,因为您尚未向交换机提供任何其他关于如何处理它们的说明(我假设有某种默认的“ all-to-controller”规则至少对于有问题的 src_ip
,否则此代码将没有意义)。然后您的控制器会丢弃这些数据包,因为 self.packets_by_ip[src_ip]
仍会大于 40。
要解决此问题,只需在 launch_countermeasures()
中安装另一个规则来转发非 tcp 数据包,
例如:
match = parser.OFPMatch(
eth_type = ether_types.ETH_TYPE_IP,ipv4_src = src_ip
)
# TODO: replace flooding with actual,sensible forwarding
actions = [parser.OFPActionOutput(OFPP_FLOOD)]
# IMPORTANT: priority for this rule is lower than for the drop rule,# because you still want tcp packets do be dropped
self.set_flow(datapath,match,actions,priority = 1)
根据不丢弃非 tcp 数据包的重要性,您可能还需要考虑在控制器上检查传入的数据包是否为 tcp。你可以这样做:
# Additional needed imports
from ryu.lib.packet import packet
from ryu.lib.packet import ether_types
from ryu.lib.packet import ethernet,ipv4
@set_ev_cls(ofp_event.EventOFPPacketIn,MAIN_DISPATCHER)
def packet_in_handler(self,ev):
data = ev.msg.data
pkt = packet.Packet(data)
eth = pkt.get_protocol(eth.eth)
if eth.ethertype == ether_types.ETH_TYPE_IP:
ip = pkt.get_protocol(ipv4.ipv4)
if not ip.proto == 6:
# is not tcp packet,insert back into datapath!