丢弃 TCP 数据包的 Python 函数 - OpenFlow

问题描述

我试图在使用 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!