Пример #1
0
    def fullTCPPacket(self):
        eth = ethernet(array('B', large_tcp))
        tcph = eth.find('tcp')
        iph = eth.find('ipv4')
        assert (tcph)
        assert (iph)
        self.checkFullTcpHeader(tcph)
        tcp2 = tcp(arr=tcph.tostring(), prev=None)
        assert (tcph.checksum() == tcph.csum)
        self.checkFullTcpHeader(tcp2)

        # check out some edge conditions
        tcp2 = tcp(arr=tcph.tostring()[:12])
        assert (not tcp2.parsed)
        tcph.off = 0
        tcp2 = tcp(arr=tcph.tostring())
        assert (not tcp2.parsed)
        tcph.off = 0xff
        tcp2 = tcp(arr=tcph.tostring())
        tcp2 = tcp(arr=tcph.tostring()[:21])
        assert (not tcp2.parsed)
        tcph.off = 0x06
        tcp2 = tcp(arr=tcph.tostring()[:25])
        assert (not tcp2.parsed)
Пример #2
0
    def fullTCPPacket(self):
        eth = ethernet(array('B',large_tcp))   
        tcph = eth.find('tcp')
        iph  = eth.find('ipv4')
        assert(tcph)
        assert(iph)
        self.checkFullTcpHeader(tcph)
        tcp2 = tcp(arr=tcph.tostring(),prev=None)
        assert(tcph.checksum() == tcph.csum)
        self.checkFullTcpHeader(tcp2)

        # check out some edge conditions
        tcp2 = tcp(arr=tcph.tostring()[:12])
        assert(not tcp2.parsed)
        tcph.off = 0
        tcp2 = tcp(arr=tcph.tostring())
        assert(not tcp2.parsed)
        tcph.off = 0xff 
        tcp2 = tcp(arr=tcph.tostring())
        tcp2 = tcp(arr=tcph.tostring()[:21])
        assert(not tcp2.parsed)
        tcph.off = 0x06 
        tcp2 = tcp(arr=tcph.tostring()[:25])
        assert(not tcp2.parsed)
Пример #3
0
    def process_packet(self, dpid, inport, packet, buf, bufid):
        """Learn MAC src port mapping, then flood or send unicast."""

        if (packet.type == ethernet.ARP_TYPE):

            # ARP packets are just kind of a hack since they aren't part of
            # our research.  They all get sent to the controller, who looks
            # at the desination IP and sends them the right way.
            arphdr = packet.next
            if (arphdr.prototype != arp.PROTO_TYPE_IP):
                return

            log.debug("GOT ARP PACKET AT DPID " + str(dpid))

            host = ip_to_str(arphdr.protodst)
            dst_node = self.g.getNodeFromClientIP(host)

            log.debug("HOST IS " + str(host) + ", dst_node is " +
                      str(dst_node))

            # Send it on to the host.
            if (dst_node == dpid):
                log.debug("SENDING TO HOST DIRECTLY")
                self.send_openflow(dpid, bufid, buf, self.portmap[dpid][host],
                                   inport)

            # Send it to the right router.
            else:
                log.debug("SENDING TO NODE " +
                          str(self.g.getNextHop(dpid, dst_node)))
                self.send_openflow(
                    dpid, bufid, buf,
                    self.portmap[dpid][self.g.getNextHop(dpid,
                                                         dst_node)], inport)

            return

        elif (packet.type == ethernet.IP_TYPE):
            iphdr = packet.next

            # Look for LEQ registration requests from services.
            if (iphdr.protocol == ipv4.UDP_PROTOCOL):
                udphdr = iphdr.next
                if (udphdr.dstport == 37823):
                    if (udphdr.len != 20):
                        return
                    request = udphdr.payload
                    log.debug("FOUND LEQ REQUEST, REGISTERING")
                    fmt = struct.Struct('! I H H H H')
                    unpacked = fmt.unpack(request)
                    alpha = float(unpacked[3]) / 100
                    x = float(unpacked[4]) / 100

                    log.debug("ALPHA IS " + str(alpha) + ", X IS " + str(x))

                    new_service = LEQ_service(
                        self.next_LEQ_id, unpacked[0], unpacked[1],
                        unpacked[2],
                        self.g.getNodeFromClientIP(ip_to_str(unpacked[0])))
                    self.next_LEQ_id += 1

                    if (new_service.protocol != 6
                            and new_service.protocol != 17):
                        return

                    # Make sure we don't already have this service.
                    for service in self.reg_LEQ_services:
                        if (new_service.ip == service.ip
                                and new_service.protocol == service.protocol
                                and new_service.port == service.port):
                            log.debug("SERVICE IS A DUPLICATE")
                            return

                    # Add the new service to the list.
                    self.reg_LEQ_services.append(new_service)

                    for service in self.reg_LEQ_services:
                        log.debug(
                            str(service.ip) + ', ' + str(service.protocol) +
                            ', ' + str(service.port))

                    # And register with the LEQ algorithm itself.
                    self.eq.registerService(service.dpid, service.id, alpha, x)

                    # Insert flow rules for each switch: whenever a new client tries
                    # to talk to a LEQ service (or vice versa), we will send the packet
                    # to the controller to perform latency equalized routing.
                    actions = [[
                        openflow.OFPAT_OUTPUT, [0, openflow.OFPP_CONTROLLER]
                    ]]

                    flow1 = {}
                    flow1[core.DL_TYPE] = ethernet.IP_TYPE
                    flow1[core.NW_PROTO] = new_service.protocol
                    flow1[NW_DST] = new_service.ip
                    flow1[TP_DST] = new_service.port

                    flow2 = {}
                    flow2[core.DL_TYPE] = ethernet.IP_TYPE
                    flow2[core.NW_PROTO] = new_service.protocol
                    flow2[NW_SRC] = new_service.ip
                    flow2[TP_SRC] = new_service.port

                    for router_id in self.routers:
                        self.install_datapath_flow(router_id,
                                                   flow1,
                                                   openflow.OFP_FLOW_PERMANENT,
                                                   openflow.OFP_FLOW_PERMANENT,
                                                   actions,
                                                   priority=0x8000)
                        self.install_datapath_flow(router_id,
                                                   flow2,
                                                   openflow.OFP_FLOW_PERMANENT,
                                                   openflow.OFP_FLOW_PERMANENT,
                                                   actions,
                                                   priority=0x8000)

                    return

            # Check if this is a packet associated with a LEQ service that is going
            # to or from a new client.
            if (iphdr.protocol == ipv4.UDP_PROTOCOL
                    or iphdr.protocol == ipv4.TCP_PROTOCOL):

                if (iphdr.protocol == ipv4.UDP_PROTOCOL):
                    sport = iphdr.next.srcport
                    dport = iphdr.next.dstport

                # The TCP case seemed to have some weird bug, perhaps in parsing, so we
                # need to get the data ourselves.
                elif (iphdr.protocol == ipv4.TCP_PROTOCOL):
                    dlen = len(iphdr.arr)
                    length = iphdr.iplen
                    if length > dlen:
                        length = dlen
                    tcphdr = tcp(arr=iphdr.arr[iphdr.hl * 4:length],
                                 prev=iphdr)
                    sport = tcphdr.srcport
                    dport = tcphdr.dstport

                log.debug("CHECKING UDP OR TCP PACKET")
                log.debug("srcip: " + str(iphdr.srcip) + ", srcport: " +
                          str(sport) + ", protocol: " + str(iphdr.protocol))
                log.debug("dstip: " + str(iphdr.dstip) + ", dstport: " +
                          str(dport) + ", protocol: " + str(iphdr.protocol))

                serv = None

                for service in self.reg_LEQ_services:
                    if (iphdr.srcip == service.ip
                            and iphdr.protocol == service.protocol
                            and sport == service.port):
                        log.debug("GOT PACKET FROM SERVICE")
                        serv = service
                        client_ip = ip_to_str(iphdr.dstip)
                        client_port = dport
                        is_to_service = False
                        break

                    elif (iphdr.dstip == service.ip
                          and iphdr.protocol == service.protocol
                          and dport == service.port):
                        log.debug("GOT PACKET TO SERVICE")
                        serv = service
                        client_ip = ip_to_str(iphdr.srcip)
                        client_port = sport
                        is_to_service = True
                        break

                if serv is None:
                    return

                if client_ip in serv.clients:
                    return

                # This is a legit new client, so add it to the service's list and
                # compute the new paths.
                log.debug("client: " + str(client_ip) + ", serv " +
                          str(serv.ip))
                serv.clients.append(client_ip)
                self.eq.addClients(serv.dpid, serv.id,
                                   [self.g.getNodeFromClientIP(client_ip)])
                changed_clients = self.eq.getUpdatedClients(serv.dpid, serv.id)

                log.debug("PATHS: " + str(self.eq.paths))

                # Add flow rules for the new paths.
                toserv_flow = {}
                toserv_flow[core.DL_TYPE] = ethernet.IP_TYPE
                toserv_flow[core.NW_PROTO] = serv.protocol
                toserv_flow[core.NW_DST] = serv.ip
                toserv_flow[core.TP_DST] = serv.port

                fromserv_flow = {}
                fromserv_flow[core.DL_TYPE] = ethernet.IP_TYPE
                fromserv_flow[core.NW_PROTO] = serv.protocol
                fromserv_flow[core.NW_SRC] = serv.ip
                fromserv_flow[core.TP_SRC] = serv.port

                for client in serv.clients:
                    client_node = self.g.getNodeFromClientIP(client)

                    # Skip clients whose path has not changed.
                    if (not (client_node in changed_clients)):
                        log.debug("Skipping client " + str(client) +
                                  " due to no change.")
                        continue

                    path = self.eq.paths[(serv.dpid, serv.id)][client_node]
                    log.debug(str(path))
                    for i in range(len(path)):
                        log.debug("path[" + str(i) + "]: " + str(path[i]))

                        # Install the client -> server rule.
                        toserv_flow[core.NW_SRC] = client

                        # to do inport, I need to set different actionsbased on the inport
                        # doesn't look like I can actually use the inport to match. only
                        # so that we don't broadcast to it when we need to

                        if (i == len(path) - 1):
                            outport = self.portmap[path[i]][ip_to_str(serv.ip)]
                            actions = [[openflow.OFPAT_OUTPUT, [0, outport]]]
                            log.debug("toserv port is " + str(outport))
                        else:
                            outport = self.portmap[path[i]][path[i + 1]]
                            actions = [[openflow.OFPAT_OUTPUT, [0, outport]]]
                            log.debug("toserv port is " + str(outport))

                        self.install_datapath_flow(path[i],
                                                   toserv_flow,
                                                   openflow.OFP_FLOW_PERMANENT,
                                                   openflow.OFP_FLOW_PERMANENT,
                                                   actions,
                                                   priority=0x9000)

                        if (client_ip == client and path[i] == dpid
                                and is_to_service == True):
                            cur_outport = outport

                        # Install the server -> client rule.
                        fromserv_flow[core.NW_DST] = client

                        if (i == 0):
                            outport = self.portmap[path[i]][client]
                            actions = [[openflow.OFPAT_OUTPUT, [0, outport]]]
                            log.debug("fromserv port is " + str(outport))
                        else:
                            outport = self.portmap[path[i]][path[i - 1]]
                            actions = [[openflow.OFPAT_OUTPUT, [0, outport]]]
                            log.debug("fromserv port is " + str(outport))

                        self.install_datapath_flow(path[i],
                                                   fromserv_flow,
                                                   openflow.OFP_FLOW_PERMANENT,
                                                   openflow.OFP_FLOW_PERMANENT,
                                                   actions,
                                                   priority=0x9000)

                        if (client_ip == client and path[i] == dpid
                                and is_to_service == False):
                            cur_outport = outport

                # Finally, send the actual packet out.
                self.send_openflow(dpid, bufid, buf, cur_outport, inport)