Navigation


Changeset 1479:c0aa1e66c12e in freeDiameter


Ignore:
Timestamp:
Mar 26, 2020, 8:28:16 AM (4 years ago)
Author:
Luke Mewburn <luke@mewburn.net>
Branch:
default
Phase:
public
Message:

csv_to_fd: improve validation

  • Validate flags:
    • Ensure M and V can't occur more than once.
    • Ensure absence of V for vendor 0.
    • Ensure presence of V for vendor not 0.
  • Ensure AVP name is unique per vendor.
  • Add AVP name to most errors.
  • Use csv.DictReader?.line_num for more accurate line numbers.

TODO: enforce M and V must be present once and only once.
Some AVPs currently fail that rule, including:

  • RFC 4005 / RFC 7155 QoS-Filter-Rule
  • 3GPP TS 29.212 PDN-Connection-ID
  • 3GPP TS 29.212 PS-to-CS-Session-Continuity
File:
1 edited

Legend:

Unmodified
Added
Removed
  • contrib/tools/csv_to_fd

    r1469 r1479  
    2424
    2525- Comment row. First cell:
    26     # Comment text      Comment text
    27     #=                  Header row of ====
     26    # Comment text      'Comment text'
     27    #=                  '/*========*/'
    2828    #                   Blank line
    2929
     
    9393
    9494    __slots__ = CSV_COLUMN_NAMES + [
    95         'filename', 'linenum', 'standard', 'vendor', ]
     95        'filename', 'line_num', 'standard', 'vendor', ]
    9696
    9797    def __init__(self, name, code, section, datatype,
    98                  must, may, shouldnot, mustnot, extra_cells,
    99                  filename='', linenum=0, standard='', vendor=0):
     98                 must, may, shouldnot, mustnot, extra_cells=[],
     99                 filename='', line_num=0, standard='', vendor=0):
    100100        # Members from CSV row
    101101        self.name = name
     
    109109        # Members from file state
    110110        self.filename = filename
    111         self.linenum = linenum
     111        self.line_num = line_num
    112112        self.standard = standard
    113113        self.vendor = vendor
     
    116116            raise ValueError('Invalid AVP name "{}"'.format(self.name))
    117117        if (self.code < 0 or self.code > 4294967295):
    118             raise ValueError('Invalid AVP code {}'.format(self.code))
     118            raise ValueError('AVP "{}" invalid code {}'.format(
     119                self.name, self.code))
    119120        if (self.datatype not in (
    120121                'OctetString', 'Integer32', 'Integer64', 'Unsigned32',
    121122                'Unsigned64', 'Float32', 'Float64', 'Grouped')
    122123                and self.datatype not in DERIVED_TO_BASE):
    123             raise ValueError('Invalid AVP data type "{}"'.format(
    124                 self.datatype))
     124            raise ValueError('AVP "{}" invalid data type "{}"'.format(
     125                self.name, self.datatype))
     126        # Validate flags
     127        flags = collections.Counter()
    125128        for val, desc in [
    126129                (self.must, 'Must'),
     
    130133                ]:
    131134            if not self._flags_re.match(val):
    132                 raise ValueError('Invalid AVP Flags {} "{}"'.format(desc, val))
     135                raise ValueError('AVP "{}" invalid {} Flags "{}"'.format(
     136                    self.name, desc, val))
     137            flags.update(val)
     138        # Check occurrence of M,V in Must,May,ShouldNot,MustNot
     139        for flag in 'MV':
     140            # TODO: can AVP flags not appear at all?
     141            # if flags[flag] == 0:
     142            #     raise ValueError('AVP "{}" Flag "{}" not set'.format(
     143            #         self.name, flag))
     144            if flags[flag] > 1:
     145                raise ValueError('AVP "{}" Flag "{}" set {} times'.format(
     146                    self.name, flag, flags[flag]))
     147        # Compare V presence against vendor
     148        if 'V' in self.must:
     149            if self.vendor == 0:
     150                raise ValueError('AVP "{}" Flag "V" set for vendor 0'.format(
     151                    self.name))
     152        else:
     153            if self.vendor != 0:
     154                raise ValueError(
     155                    'AVP "{}" Flag "V" not set for vendor {}'.format(
     156                        self.name, self.vendor))
    133157
    134158    @property
     
    169193
    170194    @abc.abstractmethod
    171     def comment(self, comment, filename, linenum):
     195    def comment(self, comment, filename, line_num):
    172196        """Process a comment row:
    173197            #comment,
     
    191215        print('AVP: {name}, {code}, {datatype}'.format(**avpdict))
    192216
    193     def comment(self, comment, filename, linenum):
     217    def comment(self, comment, filename, line_num):
    194218        print('Comment: {}'.format(comment))
    195219
     
    207231        pass
    208232
    209     def comment(self, comment, filename, linenum):
     233    def comment(self, comment, filename, line_num):
    210234        pass
    211235
     
    272296        self.add('')
    273297
    274     def comment(self, comment, filename, linenum):
     298    def comment(self, comment, filename, line_num):
    275299        if comment == '':
    276300            self.add('')
     
    353377        self.avps.append(row)
    354378
    355     def comment(self, comment, filename, linenum):
     379    def comment(self, comment, filename, line_num):
    356380        pass
    357381
     
    419443    avp_codes = collections.defaultdict(dict)
    420444
     445    # dict of [vendor][name] : Avp
     446    avp_names = collections.defaultdict(dict)
     447
    421448    # Process files
    422449    for filename in args:
     
    425452            csvdata = csv.DictReader(csvfile, CSV_COLUMN_NAMES,
    426453                                     restkey='extra_cells')
    427             linenum = 0
    428454            standard = ''
    429455            vendor = 0
    430456            for row in csvdata:
    431                 linenum += 1
    432457                try:
    433458                    if row['name'] in (None, '', 'Attribute Name'):
     
    435460                    elif row['name'].startswith('#'):
    436461                        comment = row['name'][1:]
    437                         avpproc.comment(comment, filename, linenum)
     462                        avpproc.comment(comment, filename, csvdata.line_num)
    438463                    elif row['name'].startswith('@'):
    439464                        parameter = row['name'][1:]
     
    449474                                parameter))
    450475                    else:
    451                         avp = Avp(filename=filename, linenum=linenum,
     476                        avp = Avp(filename=filename, line_num=csvdata.line_num,
    452477                                  standard=standard, vendor=vendor,
    453478                                  **row)
     
    459484                                ' in file "{}" line {}'.format(
    460485                                    avp.vendor, avp.code,
    461                                     conflict.filename, conflict.linenum))
     486                                    conflict.filename, conflict.line_num))
    462487                        avp_codes[avp.vendor][avp.code] = avp
     488                        # Ensure AVP vendor/name not already defined
     489                        if avp.name in avp_names[avp.vendor]:
     490                            conflict = avp_names[avp.vendor][avp.name]
     491                            raise ValueError(
     492                                'AVP vendor {} name "{}" already present'
     493                                ' in file "{}" line {}'.format(
     494                                    avp.vendor, avp.name,
     495                                    conflict.filename, conflict.line_num))
     496                        avp_names[avp.vendor][avp.name] = avp
    463497                        # Process AVP
    464498                        avpproc.avp(avp)
    465499                except ValueError as e:
    466                     sys.stderr.write('CSV file "{}" line {}: {}: {}\n'.format(
    467                         filename, linenum, e.__class__.__name__, e))
     500                    sys.stderr.write('CSV file "{}" line {}: {}\n'.format(
     501                        filename, csvdata.line_num, e))
    468502                    sys.exit(1)
    469503
Note: See TracChangeset for help on using the changeset viewer.