1# Copyright (c) Barefoot Networks, Inc. 2# Licensed under the Apache License, Version 2.0 (the "License") 3 4from p4_hlir.hlir import P4_SIGNED, P4_SATURATING 5from ebpfScalarType import * 6 7 8class EbpfField(object): 9 __doc__ = "represents a field in a struct type, not in an instance" 10 11 def __init__(self, hlirParentType, name, widthInBits, attributes, config): 12 self.name = name 13 self.width = widthInBits 14 self.hlirType = hlirParentType 15 signed = False 16 if P4_SIGNED in attributes: 17 signed = True 18 if P4_SATURATING in attributes: 19 raise NotSupportedException( 20 "{0}.{1}: Saturated types", self.hlirType, self.name) 21 22 try: 23 self.type = EbpfScalarType( 24 self.hlirType, widthInBits, signed, config) 25 except CompilationException, e: 26 raise CompilationException( 27 e.isBug, "{0}.{1}: {2}", hlirParentType, self.name, e.show()) 28 29 def widthInBits(self): 30 return self.width 31 32 33class EbpfStructType(EbpfType): 34 # Abstract base class for HeaderType and MetadataType. 35 # They are both represented by a p4 header_type 36 def __init__(self, hlirHeader, config): 37 super(EbpfStructType, self).__init__(hlirHeader) 38 self.name = hlirHeader.name 39 self.fields = [] 40 41 for (fieldName, fieldSize) in self.hlirType.layout.items(): 42 attributes = self.hlirType.attributes[fieldName] 43 field = EbpfField( 44 hlirHeader, fieldName, fieldSize, attributes, config) 45 self.fields.append(field) 46 47 def serialize(self, serializer): 48 assert isinstance(serializer, ProgramSerializer) 49 50 serializer.emitIndent() 51 serializer.appendFormat("struct {0} ", self.name) 52 serializer.blockStart() 53 54 for field in self.fields: 55 serializer.emitIndent() 56 field.type.declare(serializer, field.name, False) 57 serializer.appendFormat("; /* {0} bits */", field.widthInBits()) 58 serializer.newline() 59 60 serializer.blockEnd(False) 61 serializer.endOfStatement(True) 62 63 def declare(self, serializer, identifier, asPointer): 64 assert isinstance(serializer, ProgramSerializer) 65 assert isinstance(identifier, str) 66 assert isinstance(asPointer, bool) 67 68 serializer.appendFormat("struct {0} ", self.name) 69 if asPointer: 70 serializer.append("*") 71 serializer.append(identifier) 72 73 def widthInBits(self): 74 return self.hlirType.length * 8 75 76 def getField(self, name): 77 assert isinstance(name, str) 78 79 for f in self.fields: 80 assert isinstance(f, EbpfField) 81 if f.name == name: 82 return f 83 raise CompilationException( 84 True, "Could not locate field {0}.{1}", self, name) 85 86 87class EbpfHeaderType(EbpfStructType): 88 def __init__(self, hlirHeader, config): 89 super(EbpfHeaderType, self).__init__(hlirHeader, config) 90 validField = EbpfField(hlirHeader, "valid", 1, set(), config) 91 # check that no "valid" field exists already 92 for f in self.fields: 93 if f.name == "valid": 94 raise CompilationException( 95 True, 96 "Header type contains a field named `valid': {0}", 97 f) 98 self.fields.append(validField) 99 100 def emitInitializer(self, serializer): 101 assert isinstance(serializer, ProgramSerializer) 102 serializer.blockStart() 103 serializer.emitIndent() 104 serializer.appendLine(".valid = 0") 105 serializer.blockEnd(False) 106 107 def declareArray(self, serializer, identifier, size): 108 assert isinstance(serializer, ProgramSerializer) 109 serializer.appendFormat( 110 "struct {0} {1}[{2}]", self.name, identifier, size) 111 112 113class EbpfMetadataType(EbpfStructType): 114 def __init__(self, hlirHeader, config): 115 super(EbpfMetadataType, self).__init__(hlirHeader, config) 116 117 def emitInitializer(self, serializer): 118 assert isinstance(serializer, ProgramSerializer) 119 120 serializer.blockStart() 121 for field in self.fields: 122 serializer.emitIndent() 123 serializer.appendFormat(".{0} = ", field.name) 124 125 field.type.emitInitializer(serializer) 126 serializer.append(",") 127 serializer.newline() 128 serializer.blockEnd(False) 129