def __init__(self, qid, operator_id, keys, p4_raw_fields):
        super(P4MapInit, self).__init__('MapInit', qid, operator_id, keys,
                                        p4_raw_fields)

        # Add map init
        map_init_fields = list()
        for fld in self.keys:
            if fld == 'qid':
                map_init_fields.append(
                    P4Field(layer=None,
                            target_name="qid",
                            sonata_name="qid",
                            size=QID_SIZE))
            elif fld == 'count':
                map_init_fields.append(
                    P4Field(layer=None,
                            target_name="count",
                            sonata_name="count",
                            size=COUNT_SIZE))
            elif fld == 'index':
                map_init_fields.append(
                    P4Field(layer=None,
                            target_name="index",
                            sonata_name="index",
                            size=INDEX_SIZE))
            else:
                map_init_fields.append(
                    self.p4_raw_fields.get_target_field(fld))
        # create METADATA object to store data for all keys
        meta_fields = list()
        for fld in map_init_fields:
            meta_fields.append((fld.target_name.replace(".", "_"), fld.size))

        self.metadata = MetaData(self.operator_name, meta_fields)

        # create ACTION to initialize the metadata
        primitives = list()
        for fld in map_init_fields:
            sonata_name = fld.sonata_name
            target_name = fld.target_name
            meta_field_name = '%s.%s' % (self.metadata.get_name(),
                                         target_name.replace(".", "_"))

            if sonata_name == 'qid':
                # Assign query id to this field
                primitives.append(ModifyField(meta_field_name, qid))
            elif sonata_name == 'count':
                primitives.append(ModifyField(meta_field_name, 0))
            elif sonata_name == 'index':
                primitives.append(ModifyField(meta_field_name, 0))
            else:
                # Read data from raw header fields and assign them to these meta fields
                primitives.append(ModifyField(meta_field_name, target_name))

        self.action = Action('do_%s' % self.operator_name, primitives)

        # create dummy TABLE to execute the action
        self.table = Table(self.operator_name, self.action.get_name(), [],
                           None, 1)
 def mark_satisfied(self):
     primitives = list()
     primitives.append(ModifyField(self.satisfied_meta_field, 1))
     primitives.append(ModifyField(self.clone_meta_field, 1))
     self.actions['satisfied'] = Action('do_mark_satisfied_%i' % self.id,
                                        primitives)
     self.satisfied_table = Table('mark_satisfied_%i' % self.id,
                                  self.actions['satisfied'].get_name(), [],
                                  None, 1)
Example #3
0
 def append_out_header(self):
     primitives = list()
     primitives.append(AddHeader(self.out_header.get_name()))
     for fld in self.out_header.fields:
         primitives.append(ModifyField('%s.%s' % (self.out_header.get_name(), fld.target_name.replace(".", "_")),
                                       '%s.%s' % (self.meta_init_name, fld.target_name.replace(".", "_"))))
     self.actions['append_out_header'] = Action('do_add_out_header_%i' % self.id, primitives)
     self.out_header_table = Table('add_out_header_%i' % self.id, self.actions['append_out_header'].get_name(), [],
                                   None, 1)
Example #4
0
    def init_application(self, app):
        queries = dict()

        # define final header
        # TODO: Use new p4 layer object
        tmp = OutHeaders("final_header")
        tmp.fields = [P4Field(tmp, "delimiter", "delimiter", 32)]
        self.final_header = tmp

        primitives = list()
        primitives.append(AddHeader(self.final_header.get_name()))
        primitives.append(ModifyField('%s.delimiter' % self.final_header.get_name(), 0))
        self.final_header_action = Action('do_add_final_header', primitives)

        self.final_header_table = Table('add_final_header', self.final_header_action.get_name(), [], None, 1)

        # define nop action
        self.nop_action = Action('_nop', NoOp())
        nop_name = self.nop_action.get_name()

        # app metadata
        fields = list()
        for query_id in app:
            fields.append(('%s_%i' % (self.drop_meta_field, query_id), 1))
            fields.append(('%s_%i' % (self.satisfied_meta_field, query_id), 1))
        fields.append((self.clone_meta_field, 1))
        self.metadata = MetaData('app_data', fields)
        meta_name = self.metadata.get_name()

        # action and table to init app metadata
        primitives = list()
        for field_name, _ in fields:
            primitives.append(ModifyField('%s.%s' % (self.metadata.get_name(), field_name), 0))
        self.init_action = Action('do_init_app_metadata', primitives)

        self.init_action_table = Table('init_app_metadata', self.init_action.get_name(), [], None, 1)

        # transforms queries
        for query_id in app:
            self.logger.debug('create query pipeline for qid: %i' % (query_id))
            parse_payload = app[query_id].parse_payload
            payload_fields = app[query_id].payload_fields
            read_register = app[query_id].read_register
            filter_payload = app[query_id].filter_payload
            filter_payload_str = app[query_id].filter_payload_str
            operators = app[query_id].operators
            query = P4Query(query_id,
                            parse_payload,
                            payload_fields,
                            read_register,
                            filter_payload,
                            filter_payload_str,
                            operators,
                            nop_name,
                            '%s.%s' % (meta_name, self.drop_meta_field),
                            '%s.%s' % (meta_name, self.satisfied_meta_field),
                            '%s.%s' % (meta_name, self.clone_meta_field), self.p4_raw_fields)
            queries[query_id] = query

        # define mirroring session
        self.mirror_session = MirrorSession(SESSION_ID, SPAN_PORT)

        # define report action that clones the packet and sends it to the stream processor
        fields = [self.metadata.get_name()]
        for query in queries.values():
            fields.append(query.get_metadata_name())
        self.field_list = FieldList('report_packet', fields)

        self.report_action = Action('do_report_packet', CloneIngressPktToEgress(self.mirror_session.get_session_id(),
                                                                                self.field_list.get_name()))

        self.report_action_table = Table('report_packet', self.report_action.get_name(), [], None, 1)
        return queries
 def add_general_drop_action(self):
     self.actions['drop'] = Action('drop_%i' % self.id,
                                   (ModifyField(self.drop_meta_field, 1)))
     self.query_drop_action = self.actions['drop'].get_name()
    def __init__(self, qid, operator_id, meta_init_name, keys, map_keys,
                 map_values, func, p4_raw_fields):
        super(P4Map, self).__init__('Map', qid, operator_id, keys,
                                    p4_raw_fields)

        self.meta_init_name = meta_init_name
        self.map_keys = map_keys
        self.func = func
        self.map_values = map_values

        # Add map init
        map_fields = list()
        for fld in self.map_keys:
            if fld == 'qid':
                map_fields.append(
                    P4Field(layer=None,
                            target_name="qid",
                            sonata_name="qid",
                            size=QID_SIZE))
            elif fld == 'count':
                map_fields.append(
                    P4Field(layer=None,
                            target_name="count",
                            sonata_name="count",
                            size=COUNT_SIZE))
            else:
                map_fields.append(self.p4_raw_fields.get_target_field(fld))

        map_fields_values = list()
        for fld in self.map_values:
            if fld == 'qid':
                map_fields_values.append(
                    P4Field(layer=None,
                            target_name="qid",
                            sonata_name="qid",
                            size=QID_SIZE))
            elif fld == 'count':
                map_fields_values.append(
                    P4Field(layer=None,
                            target_name="count",
                            sonata_name="count",
                            size=COUNT_SIZE))
            else:
                map_fields_values.append(
                    self.p4_raw_fields.get_target_field(fld))

        # create ACTION using the function
        primitives = list()
        if len(func) > 0:
            self.func = func
            if func[0] == 'mask' or not func[0]:
                for field in map_fields:
                    mask_size = (func[1] / 4)
                    mask = '0x' + ('f' * mask_size) + (
                        '0' *
                        (HEADER_MASK_SIZE[field.target_name] - mask_size))
                    field_name = '%s.%s' % (self.meta_init_name,
                                            field.target_name.replace(
                                                ".", "_"))
                    primitives.append(BitAnd(field_name, field_name, mask))
            if func[0] == 'set' or not func[0]:
                for field in map_fields_values:
                    field_name = '%s.%s' % (self.meta_init_name,
                                            field.target_name.replace(
                                                ".", "_"))
                    primitives.append(ModifyField(field_name, func[1]))

        self.action = Action('do_%s' % self.operator_name, primitives)

        # create dummy TABLE to execute the action
        self.table = Table(self.operator_name, self.action.get_name(), [],
                           None, 1)
    def __init__(self, qid, operator_id, meta_init_name, drop_action, keys,
                 values, threshold, read_register, p4_raw_fields):
        super(P4Reduce, self).__init__('Reduce', qid, operator_id, keys,
                                       p4_raw_fields)

        if threshold == '-1':
            self.threshold = int(THRESHOLD)
        else:
            self.threshold = int(threshold)

        self.read_register = read_register

        if self.read_register:
            self.out_headers += ['index']
        else:
            self.out_headers += ['count']

        # create METADATA to store index and value
        fields = [('value', REGISTER_WIDTH),
                  ('index', REGISTER_NUM_INDEX_BITS)]
        self.metadata = MetaData(self.operator_name, fields)

        # create REGISTER to keep track of counts
        self.register = Register(self.operator_name, REGISTER_WIDTH,
                                 REGISTER_INSTANCE_COUNT)

        self.values = values

        # Add map init
        hash_init_fields = list()
        for fld in self.keys:
            if fld == 'qid':
                hash_init_fields.append(
                    P4Field(layer=None,
                            target_name="qid",
                            sonata_name="qid",
                            size=QID_SIZE))
            elif fld == 'count':
                hash_init_fields.append(
                    P4Field(layer=None,
                            target_name="count",
                            sonata_name="count",
                            size=COUNT_SIZE))
            elif fld == 'index':
                hash_init_fields.append(
                    P4Field(layer=None,
                            target_name="index",
                            sonata_name="index",
                            size=INDEX_SIZE))
            else:
                hash_init_fields.append(
                    self.p4_raw_fields.get_target_field(fld))
        # create HASH for access to register
        hash_fields = list()
        for field in hash_init_fields:
            if '/' in field.sonata_name:
                self.logger.error('found a / in the key')
                raise NotImplementedError
            else:
                hash_fields.append(
                    '%s.%s' %
                    (meta_init_name, field.target_name.replace(".", "_")))
        self.hash = HashFields(self.operator_name, hash_fields, 'crc16',
                               REGISTER_NUM_INDEX_BITS)

        # name of metadata field where the index of the count within the register is stored
        self.index_field_name = '%s.index' % self.metadata.get_name()
        # name of metadata field where the count is kept temporarily
        self.value_field_name = '%s.value' % self.metadata.get_name()

        # create ACTION and TABLE to compute hash and get value
        primitives = list()
        primitives.append(
            ModifyFieldWithHashBasedOffset(self.index_field_name, 0,
                                           self.hash.get_name(),
                                           REGISTER_INSTANCE_COUNT))
        primitives.append(
            RegisterRead(self.value_field_name, self.register.get_name(),
                         self.index_field_name))

        if self.values[0] == 'count':
            if self.threshold <= 1:
                self.threshold = '1'

            primitives.append(
                ModifyField(self.value_field_name,
                            '%s + %i' % (self.value_field_name, 1)))
        else:
            target_fld = self.p4_raw_fields.get_target_field(self.values[0])
            if self.threshold <= 1:
                self.threshold = '%s.%s' % (
                    meta_init_name, target_fld.target_name.replace(".", "_"))

            primitives.append(
                ModifyField(
                    self.value_field_name,
                    '%s + %s' % (self.value_field_name, '%s.%s' %
                                 (meta_init_name,
                                  target_fld.target_name.replace(".", "_")))))

        primitives.append(
            RegisterWrite(self.register.get_name(), self.index_field_name,
                          self.value_field_name))
        self.init_action = Action('do_init_%s' % self.operator_name,
                                  primitives)
        table_name = 'init_%s' % self.operator_name
        self.init_table = Table(table_name, self.init_action.get_name(), [],
                                None, 1)

        # create three TABLEs that implement reduce operation
        # if count <= THRESHOLD, update count and drop,
        table_name = 'drop_%s' % self.operator_name
        self.drop_table = Table(table_name, drop_action, [], None, 1)

        # if count == THRESHOLD, pass through with current count
        field_to_modified = None
        if not self.read_register:
            field_to_modified = ModifyField('%s.count' % meta_init_name,
                                            self.value_field_name)
        else:
            field_to_modified = ModifyField('%s.index' % meta_init_name,
                                            self.index_field_name)

        self.set_count_action = Action('set_count_%s' % self.operator_name,
                                       field_to_modified)
        table_name = 'first_pass_%s' % self.operator_name
        self.first_pass_table = Table(table_name,
                                      self.set_count_action.get_name(), [],
                                      None, 1)

        if not self.read_register:
            # if count > THRESHOLD, let it pass through with count set to 1
            self.reset_count_action = Action(
                'reset_count_%s' % self.operator_name,
                ModifyField('%s.count' % meta_init_name, 1))
            table_name = 'pass_%s' % self.operator_name
            self.pass_table = Table(table_name,
                                    self.reset_count_action.get_name(), [],
                                    None, 1)