예제 #1
0
    def __init__(self, grpc_addr, device_id, device, election_id, role_id,
                 config_path, p4info_path, ctx_json):
        self.grpc_addr = grpc_addr
        if self.grpc_addr is None:
            self.grpc_addr = 'localhost:50051'

        self.device_id = int(device_id)
        if self.device_id is None:
            print("Device ID is not set")

        self.device = device

        self.config_path = config_path
        self.p4info_path = p4info_path
        self.ctx_json_path = ctx_json

        self.channel = grpc.insecure_channel(self.grpc_addr)
        self.stub = p4runtime_pb2.P4RuntimeStub(self.channel)

        print "Importing p4info proto from", p4info_path
        self.p4info = p4info_pb2.P4Info()
        with open(p4info_path, "rb") as fin:
            google.protobuf.text_format.Merge(fin.read(), self.p4info)

        self.p4info_helper = helper.P4InfoHelper(p4info_path)

        self.import_p4info_names()

        # used to store write requests sent to the P4Runtime server, useful for
        # autocleanup of tests (see definition of autocleanup decorator below)
        self.reqs = []

        self.election_id = election_id
        self.role_id = role_id
        self.set_up_stream()
예제 #2
0
def ConfigureNetwork(p4info_file="build/data_plane.p4info",
                     bmv2_json="build/data_plane.json"):
    p4info_helper = helper.P4InfoHelper(p4info_file)

    threads = []

    print "Connecting to P4Runtime server on s1..."
    sw1 = bmv2.Bmv2SwitchConnection('s1', "127.0.0.1:50051", 0)
    sw1.MasterArbitrationUpdate()
    sw1.SetForwardingPipelineConfig(p4info=p4info_helper.p4info,
                                    bmv2_json_file_path=bmv2_json)
    t = threading.Thread(target=RunControlPlane, args=(sw1, 1, p4info_helper))
    t.start()
    threads.append(t)

    print "Connecting to P4Runtime server on s2..."
    sw2 = bmv2.Bmv2SwitchConnection('s2', "127.0.0.1:50052", 1)
    sw2.MasterArbitrationUpdate()
    sw2.SetForwardingPipelineConfig(p4info=p4info_helper.p4info,
                                    bmv2_json_file_path=bmv2_json)
    t = threading.Thread(target=RunControlPlane, args=(sw2, 2, p4info_helper))
    t.start()
    threads.append(t)

    print "Connecting to P4Runtime server on s3..."
    sw3 = bmv2.Bmv2SwitchConnection('s3', "127.0.0.1:50053", 2)
    sw3.MasterArbitrationUpdate()
    sw3.SetForwardingPipelineConfig(p4info=p4info_helper.p4info,
                                    bmv2_json_file_path=bmv2_json)
    t = threading.Thread(target=RunControlPlane, args=(sw3, 3, p4info_helper))
    t.start()
    threads.append(t)

    for t in threads:
        t.join()
예제 #3
0
def ConfigureNetwork(p4info_file="build/data_plane.p4info",
                     bmv2_json="build/data_plane.json",
                     topology_json="topology2.json"):
    p4info_helper = helper.P4InfoHelper(p4info_file)
    with open(topology_json, 'r') as f:
        routers = json.load(f, object_pairs_hook=OrderedDict)['routers']

    threads = []
    port = 50051
    id_num = 0

    for name, config in routers.items():
        config = byteify(config)

        print "Connecting to P4Runtime server on {}...".format(name)
        r = bmv2.Bmv2SwitchConnection(name, "127.0.0.1:" + str(port), id_num)
        r.MasterArbitrationUpdate()
        r.SetForwardingPipelineConfig(p4info=p4info_helper.p4info,
                                      bmv2_json_file_path=bmv2_json)
        t = threading.Thread(target=RunControlPlane,
                             args=(r, config, p4info_helper))
        t.start()
        threads.append(t)

        port += 1
        id_num += 1

    for t in threads:
        t.join()
예제 #4
0
def program_switch(addr, device_id, sw_conf_file, workdir, proto_dump_fpath):
    sw_conf = json_load_byteified(sw_conf_file)
    try:
        check_switch_conf(sw_conf=sw_conf, workdir=workdir)
    except ConfException as e:
        error("While parsing input runtime configuration: %s" % str(e))
        return

    info('Using P4Info file %s...' % sw_conf['p4info'])
    p4info_fpath = os.path.join(workdir, sw_conf['p4info'])
    p4info_helper = helper.P4InfoHelper(p4info_fpath)

    target = sw_conf['target']

    info("Connecting to P4Runtime server on %s (%s)..." % (addr, target))

    if target == "bmv2":
        sw = bmv2.Bmv2SwitchConnection(address=addr,
                                       device_id=device_id,
                                       proto_dump_file=proto_dump_fpath)
    else:
        raise Exception("Don't know how to connect to target %s" % target)

    try:
        sw.MasterArbitrationUpdate()

        if target == "bmv2":
            info("Setting pipeline config (%s)..." % sw_conf['bmv2_json'])
            bmv2_json_fpath = os.path.join(workdir, sw_conf['bmv2_json'])
            sw.SetForwardingPipelineConfig(p4info=p4info_helper.p4info,
                                           bmv2_json_file_path=bmv2_json_fpath)
        else:
            raise Exception("Should not be here")

        if 'table_entries' in sw_conf:
            table_entries = sw_conf['table_entries']
            info("Inserting %d table entries..." % len(table_entries))
            for entry in table_entries:
                info(tableEntryToString(entry))
                insertTableEntry(sw, entry, p4info_helper)

        if 'multicast_group_entries' in sw_conf:
            group_entries = sw_conf['multicast_group_entries']
            info("Inserting %d group entries..." % len(group_entries))
            for entry in group_entries:
                info(groupEntryToString(entry))
                insertMulticastGroupEntry(sw, entry, p4info_helper)

        if 'clone_session_entries' in sw_conf:
            clone_entries = sw_conf['clone_session_entries']
            info("Inserting %d clone entries..." % len(clone_entries))
            for entry in clone_entries:
                info(cloneEntryToString(entry))
                insertCloneGroupEntry(sw, entry, p4info_helper)

    finally:
        sw.shutdown()
예제 #5
0
def install_s1__entry_rule():  # DO NOT USE
    # ALREADY DONE IN s1-runtime.json
    # INTENDED AS AN EXAMPLE FOR FUTURE DEVELOPMENT

    #!/usr/bin/env python2
    import grpc
    import os
    from time import sleep

    # Import P4Runtime lib from parent utils dir
    # Probably there's a better way of doing this.
    sys.path.append(
        os.path.join(os.path.dirname(os.path.abspath(__file__)),
                     'utils/p4runtime_lib'))
    import bmv2
    from error_utils import printGrpcError
    from switch import ShutdownAllSwitchConnections
    import helper

    p4info_file_path = "build/Raft.p4.p4info.txt"
    p4info_helper = helper.P4InfoHelper(p4info_file_path)

    s1 = bmv2.Bmv2SwitchConnection(
        name='s1',
        address='127.0.0.1:50051',
        device_id=0,
        proto_dump_file='logs/s1-p4runtime-requests_my_py.txt')

    s1.MasterArbitrationUpdate()

    table_entry = p4info_helper.buildTableEntry(
        table_name="MyIngress.leader",
        match_fields={
            "meta.raft_metadata.role": 2,
            "hdr.raft.messageType": 2
        },
        action_name="MyIngress.spread_new_request",
        action_params={})

    table_entry2 = p4info_helper.buildTableEntry(
        table_name="MyIngress.follower",
        match_fields={
            "meta.raft_metadata.role": 0,
            "hdr.raft.messageType": 10,
            "hdr.ipv4.dstAddr": ["10.0.1.254", 32]
        },
        action_name="MyIngress.follower_timeout",
        action_params={})

    s1.WriteTableEntry(table_entry)
    s1.WriteTableEntry(table_entry2)
    print("Installed leader table entry rule on {}".format(s1.name))
예제 #6
0
def program_switch(addr, device_id, sw_conf_file, workdir, proto_dump_fpath):
    sw_conf = json_load_byteified(sw_conf_file)
    try:
        check_switch_conf(sw_conf=sw_conf, workdir=workdir)
    except ConfException as e:
        error("While parsing input runtime configuration: %s" % str(e))
        return

    info('Using P4Info file %s...' % sw_conf['p4info'])  # basic.p4info
    p4info_fpath = os.path.join(workdir, sw_conf['p4info'])
    p4info_helper = helper.P4InfoHelper(p4info_fpath)

    target = sw_conf['target']

    info("Connecting to P4Runtime server on %s (%s)..." % (addr, target))

    if target == "bmv2":
        sw = bmv2.Bmv2SwitchConnection(
            address=addr,
            device_id=device_id,  # Bmv2SwitchConnection extends SwitchConnection
            proto_dump_file=proto_dump_fpath)  # p4info is not set
    else:
        raise Exception("Don't know how to connect to target %s" % target)

    try:
        sw.MasterArbitrationUpdate()
        if target == "bmv2":
            info("Setting pipeline config (%s)..." %
                 sw_conf['bmv2_json'])  # p4c compiled json file
            bmv2_json_fpath = os.path.join(workdir, sw_conf['bmv2_json'])
            print("bmv2_json_fpath---", bmv2_json_fpath)
            # set p4info and p4c compiled json file to switch
            sw.SetForwardingPipelineConfig(
                p4info=p4info_helper.p4info,  # p4info is in
                bmv2_json_file_path=bmv2_json_fpath
            )  # set p4c compiled json file
        else:
            raise Exception("Should not be here")

        if 'table_entries' in sw_conf:
            table_entries = sw_conf['table_entries']
            info("Inserting %d table entries..." % len(table_entries))
            for entry in table_entries:
                info(tableEntryToString(entry))
                insertTableEntry(sw, entry, p4info_helper)
    finally:
        #print("continue")
        sw.shutdown()
예제 #7
0
def reset_switch(addr, device_id, sw_conf_file, workdir, proto_dump_fpath):
    sw_conf = json_load_byteified(sw_conf_file)
    try:
        check_switch_conf(sw_conf=sw_conf, workdir=workdir)
    except ConfException as e:
        error("While parsing input runtime configuration: %s" % str(e))
        return

    p4info_fpath = os.path.join(workdir, sw_conf['p4info'])
    p4info_helper = helper.P4InfoHelper(p4info_fpath)

    target = sw_conf['target']

    if target == "bmv2":
        sw = bmv2.Bmv2SwitchConnection(address=addr,
                                       device_id=device_id,
                                       proto_dump_file=proto_dump_fpath)
    else:
        raise Exception("Don't know how to connect to target %s" % target)

    try:
        sw.MasterArbitrationUpdate()

        if target == "bmv2":
            bmv2_json_fpath = os.path.join(workdir, sw_conf['bmv2_json'])
            sw.SetForwardingPipelineConfig(p4info=p4info_helper.p4info,
                                           bmv2_json_file_path=bmv2_json_fpath)
        else:
            raise Exception("Should not be here")

        if 'table_entries' in sw_conf:
            table_entries = sw_conf['table_entries']
            for entry in table_entries:
                insertTableEntry(sw, entry, p4info_helper)
                deleteTableEntry(sw, entry, p4info_helper)
    finally:
        sw.shutdown()
예제 #8
0
    parser = argparse.ArgumentParser(description='CIS553 P4Runtime Controller')

    parser.add_argument("-b", '--bmv2-json',
                        help="path to BMv2 switch description (json)",
                        type=str, action="store", default="build/basic.json")
    parser.add_argument("-c", '--p4info-file',
                        help="path to P4Runtime protobuf description (text)",
                        type=str, action="store", default="build/basic.p4info")

    args = parser.parse_args()

    if not os.path.exists(args.p4info_file):
        parser.error("File %s does not exist!" % args.p4info_file)
    if not os.path.exists(args.bmv2_json):
        parser.error("File %s does not exist!" % args.bmv2_json)
    p4info_helper = helper.P4InfoHelper(args.p4info_file)


    threads = []

    print "Connecting to P4Runtime server on s1..."
    sw1 = bmv2.Bmv2SwitchConnection('s1', "127.0.0.1:50051", 0)
    sw1.MasterArbitrationUpdate()
    sw1.SetForwardingPipelineConfig(p4info = p4info_helper.p4info,
                                    bmv2_json_file_path = args.bmv2_json)
    t = threading.Thread(target=ProgramSwitch, args=(sw1, 1, p4info_helper))
    t.start()
    threads.append(t)

    print "Connecting to P4Runtime server on s2..."
    sw2 = bmv2.Bmv2SwitchConnection('s2', "127.0.0.1:50052", 1)
예제 #9
0
import grpc
import os, sys
from time import sleep

# Import P4Runtime lib from parent utils dir
# Probably there's a better way of doing this.
sys.path.append(
    os.path.join(os.path.dirname(os.path.abspath(__file__)),
                 'utils/p4runtime_lib'))
import bmv2
from error_utils import printGrpcError
from switch import ShutdownAllSwitchConnections
import helper

p4info_file_path = "build/Raft.p4.p4info.txt"
p4info_helper = helper.P4InfoHelper(p4info_file_path)

s1 = bmv2.Bmv2SwitchConnection(
    name='s1',
    address='127.0.0.1:50051',
    device_id=0,
    proto_dump_file='logs/s1-p4runtime-requests_my_py.txt')

s1.MasterArbitrationUpdate()

table_entry2 = p4info_helper.buildTableEntry(
    table_name="MyIngress.follower",
    match_fields={
        "meta.raft_metadata.role": 0,
        "hdr.raft.messageType": 10,
        "hdr.ipv4.dstAddr": [0x0, 0xa, 1]
예제 #10
0
    def __init__(self,
                 name=None,
                 address="127.0.0.1:50051",
                 device_id=0,
                 p4info_file_path=None,
                 proto_dump_file=None,
                 p4configjson=None,
                 toFlowID=0xffff0000,
                 queueDepth=1000,
                 queueRate=1000,
                 thriftPort=9090,
                 controlPlaneDelay=0):
        self.name = name
        self.toFlowID = toFlowID
        self.address = address
        self.device_id = device_id
        self.swNum = device_id + 1
        self.p4info = None
        self.bmv2_json_file_path = NotImplemented  # set this at programming time
        self.p4info_file_path = p4info_file_path
        self.p4info_helper = p4runtime_lib_helper.P4InfoHelper(
            p4info_file_path)
        self.channel = grpc.insecure_channel(self.address)
        if proto_dump_file is not None:
            interceptor = GrpcRequestLogger(proto_dump_file)
            self.channel = grpc.intercept_channel(self.channel, interceptor)
        self.client_stub = p4runtime_pb2_grpc.P4RuntimeStub(self.channel)
        self.proto_dump_file = proto_dump_file
        self.p4configjson = p4configjson
        ## below is from me:
        self.stop = False
        self.defaultRules = []
        self.activePorts = {}
        self.activePorts[1] = 0
        self.inactivePorts = []
        self.activeServices = {}
        self.master = False
        self.stream_out_q = Queue()
        self.qlogfile = open('logs/' + str(self.device_id) + '.log', "w+")
        self.qlogfileFirst = False
        self.numdigest = 0
        self.vnfList = []
        self.services = []
        self.flowRates = {}
        self.queueDepth = queueDepth
        self.thriftPort = thriftPort
        self.queueRate = queueRate
        self.overloadDetected = False
        self.migThreads = []
        self.controlPlaneDelay = controlPlaneDelay
        self.overloading = 0

        def stream_req_iterator():
            while True:
                p = self.stream_out_q.get()
                if p is None:
                    break
                yield p

        def stream_recv(self):
            i = 0
            #pr = cProfile.Profile()
            for msg in self.stream:
                tStart = time()
                if msg.HasField('packet'):
                    if msg.packet.payload.encode(
                            'hex')[0:4] == '3341' or msg.packet.payload.encode(
                                'hex')[0:4] == '3143':
                        #print msg.packet.payload.encode('hex') + ' recevied from ' + str(self.name)
                        if (msg.packet.payload.encode('hex')[20] == str(
                                self.swNum) and
                            (msg.packet.payload.encode('hex')[0:4] == '3341')):
                            # this packet is a sync thing received from a migration source:
                            #print msg.packet.payload.encode('hex')
                            migThread = threading.Thread(target=self.doCPSYnc,
                                                         args=(msg, ))
                            migThread.start()
                        else:
                            migThread = threading.Thread(
                                target=self.processMigPkt, args=(msg, ))
                            migThread.start()
                        #print "processing migpacket took %f seconds"% float(time() - tStart)
                    else:
                        pkt = controlPacket.controlPacket(msg,
                                                          self.name,
                                                          ts=float(tStart))
                        # # break if no valid ethtype can be derived
                        if hasattr(pkt.eth, 'type') and pkt.eth != None:
                            discList = [0xffff, 0xffee, 0xeffe]
                            ignoreList = [0x86dd, 0x0806]
                            if pkt.eth.type in discList:
                                thread = threading.Thread(
                                    target=self.processDiscPacket,
                                    args=(pkt, ))
                                thread.start()
                                continue
                            elif hex(pkt.eth.type
                                     ) not in ignoreList and pkt.ip != None:
                                thread = threading.Thread(
                                    target=self.processpacketIn, args=(pkt, ))
                                thread.start()
                elif msg.HasField('arbitration'):
                    print('arbitration packet recieved!')
                    if not msg.arbitration.status.message == "Is master":
                        print('Error setting controller as master for device')
                    else:
                        self.master = True
                elif msg.HasField('digest'):
                    # Digest message received. Send digestACK back:
                    self.digestMessageACK(msg.digest.digest_id,
                                          msg.digest.list_id)
                    self.numdigest += 1
                    digFields = self.p4info_helper.get_digest_fields_by_id(
                        msg.digest.digest_id)
                    # convert message to json format:
                    dictMsg = google.protobuf.json_format.MessageToDict(msg)
                    # read information to a dictionary:
                    infoDict = {}
                    printVals = []
                    printHdrs = []
                    enq_qdepth = None
                    deq_qdepth = None
                    deq_timedelta = None
                    threshold = None
                    timestamp = None
                    flowID = None
                    numPackets = None
                    enq_timestamp = None
                    for x in range(0, len(digFields)):
                        for y in digFields[x]:
                            infoDict[y] = {}
                            infoDict[y]['value'] = int(
                                bytes(
                                    base64.decodestring(
                                        dictMsg['digest']['data'][0]['struct']
                                        ['members'][x]['bitstring'])).encode(
                                            'hex'), 16)
                            infoDict[y]['bitlength'] = digFields[x][y]
                            if self.qlogfileFirst == False:
                                printHdrs.append(str(y))
                            printVals.append(infoDict[y]['value'])
                            if False == True:
                                print '%s, (%i bit): %i' % (
                                    y, infoDict[y]['bitlength'],
                                    infoDict[y]['value'])
                            # save values
                            if str(y) == str('enq_qdepth'):
                                enq_qdepth = infoDict[y]['value']
                            if str(y) == str('deq_qdepth'):
                                deq_qdepth = infoDict[y]['value']
                            if str(y) == str('deq_timedelta'):
                                deq_timedelta = float(
                                    infoDict[y]['value']) / float(
                                        1000000)  # convert to ms
                            if str(y) == str('threshold'):
                                threshold = infoDict[y]['value']
                            if str(y) == str('timestamp'):
                                timestamp = infoDict[y]['value']
                            if str(y) == str('flowID'):
                                flowID = infoDict[y]['value']
                            if str(y) == str('numPackets'):
                                numPackets = infoDict[y]['value']
                            if str(y) == str('enq_timestamp'):
                                enq_timestamp = infoDict[y]['value']

                    if enq_qdepth != None and deq_qdepth != None and deq_timedelta != None and enq_timestamp != None:
                        # print 'SWITCH OVERLOADING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!'
                        # print "enq_qdepth %s" % enq_qdepth
                        # print "deq_qdepth %s" % deq_qdepth
                        # print "deq_timedelta %s" % deq_timedelta

                        # figure out what to do
                        # create a thread that runs the checks for migration and initializes the migration.
                        # runMigration = False
                        # if self.overloadDetected == False:
                        #     runMigration = True
                        # # try:
                        # #     if (time() - float(self.overloadDetected)) > float(10):
                        # #         runMigration = True
                        # # except:
                        # #     pass

                        t = threading.Thread(target=pktMon.addpktDigestReading,
                                             args=(self.name, enq_qdepth,
                                                   deq_qdepth, deq_timedelta,
                                                   enq_timestamp))
                        t.start()
                        #print 'enqdepth: %i, deqdepth:%i' % (enq_qdepth, deq_qdepth)

                        if (enq_qdepth < deq_qdepth) and (deq_qdepth > 20):
                            #print "enqQdepth: %f deqQdepth: %f" %(float(enq_qdepth), float(deq_qdepth))
                            # NO SCALING IF CONTINUE BELOW HERE!
                            #continue
                            if self.overloadDetected == False:  # and self.overloading > 5:
                                self.overloadDetected = tStart
                                migrateThread = threading.Thread(
                                    target=flowHandler.migrationHandler,
                                    args=(self, enq_timestamp))
                                migrateThread.start()
                                print('Switch %s overloading!!!!' % self.name)

                        # Start the procedure to redirect the load to an other switch (if possible).
                        # if no solution exists, a new hardware switch should be added.

                        # This can be a problem....
                    elif threshold != None and timestamp != None and flowID != None and numPackets != None:
                        # this is a packet for rates....
                        t = threading.Thread(target=flowMonitor.addReading,
                                             args=(flowID, timestamp,
                                                   numPackets, self))
                        t.start()
                        #flowMonitor.addReading(flowID, timestamp, numPackets, self)
                        #print "%i/%i at timestamp %i for flowID %s from switch %s" % (numPackets, threshold, timestamp, flowID, self.name)
                    else:
                        print ' begin hellup'
                        if enq_qdepth == None:
                            print 'enq_qdepth is none'
                        if deq_qdepth == None:
                            print 'deq_qdepth is none'
                        if deq_timedelta == None:
                            print 'deq_timedelta is none'
                        print ' eind hellup'
                    # # writ things to file
                    # if self.qlogfileFirst == False:
                    #     self.qlogfile.write(str(printHdrs) + '\n')
                    #     self.qlogfileFirst = True

                    # self.qlogfile.write(str(printVals) + '\n')
                else:
                    print('unknown packet received')
                # has completed successfully
                tElapsed = time() - tStart
                #print("Elapsed time for packetin/out: %.20f ms" %(tElapsed * 1000))

        self.stream = self.client_stub.StreamChannel(stream_req_iterator())
        self.stream_recv_thread = threading.Thread(target=stream_recv,
                                                   args=(self, ))
        self.stream_recv_thread.start()

        # send masterarbitrationupdate:
        req = p4runtime_pb2.StreamMessageRequest()
        arbitration = req.arbitration
        arbitration.device_id = self.device_id
        arbitration.election_id.high = 0
        arbitration.election_id.low = 1
        self.stream_out_q.put(req)
        switchFinder.addSwitch(self)