blob: 8efa2d2c24c2fa0be17eec3866cb3d726a096489 [file] [log] [blame]
# Copyright (c) Barefoot Networks, Inc.
# Licensed under the Apache License, Version 2.0 (the "License")
from p4_hlir.hlir import P4_SIGNED, P4_SATURATING
from ebpfScalarType import *
class EbpfField(object):
__doc__ = "represents a field in a struct type, not in an instance"
def __init__(self, hlirParentType, name, widthInBits, attributes, config):
self.name = name
self.width = widthInBits
self.hlirType = hlirParentType
signed = False
if P4_SIGNED in attributes:
signed = True
if P4_SATURATING in attributes:
raise NotSupportedException(
"{0}.{1}: Saturated types", self.hlirType, self.name)
try:
self.type = EbpfScalarType(
self.hlirType, widthInBits, signed, config)
except CompilationException, e:
raise CompilationException(
e.isBug, "{0}.{1}: {2}", hlirParentType, self.name, e.show())
def widthInBits(self):
return self.width
class EbpfStructType(EbpfType):
# Abstract base class for HeaderType and MetadataType.
# They are both represented by a p4 header_type
def __init__(self, hlirHeader, config):
super(EbpfStructType, self).__init__(hlirHeader)
self.name = hlirHeader.name
self.fields = []
for (fieldName, fieldSize) in self.hlirType.layout.items():
attributes = self.hlirType.attributes[fieldName]
field = EbpfField(
hlirHeader, fieldName, fieldSize, attributes, config)
self.fields.append(field)
def serialize(self, serializer):
assert isinstance(serializer, ProgramSerializer)
serializer.emitIndent()
serializer.appendFormat("struct {0} ", self.name)
serializer.blockStart()
for field in self.fields:
serializer.emitIndent()
field.type.declare(serializer, field.name, False)
serializer.appendFormat("; /* {0} bits */", field.widthInBits())
serializer.newline()
serializer.blockEnd(False)
serializer.endOfStatement(True)
def declare(self, serializer, identifier, asPointer):
assert isinstance(serializer, ProgramSerializer)
assert isinstance(identifier, str)
assert isinstance(asPointer, bool)
serializer.appendFormat("struct {0} ", self.name)
if asPointer:
serializer.append("*")
serializer.append(identifier)
def widthInBits(self):
return self.hlirType.length * 8
def getField(self, name):
assert isinstance(name, str)
for f in self.fields:
assert isinstance(f, EbpfField)
if f.name == name:
return f
raise CompilationException(
True, "Could not locate field {0}.{1}", self, name)
class EbpfHeaderType(EbpfStructType):
def __init__(self, hlirHeader, config):
super(EbpfHeaderType, self).__init__(hlirHeader, config)
validField = EbpfField(hlirHeader, "valid", 1, set(), config)
# check that no "valid" field exists already
for f in self.fields:
if f.name == "valid":
raise CompilationException(
True,
"Header type contains a field named `valid': {0}",
f)
self.fields.append(validField)
def emitInitializer(self, serializer):
assert isinstance(serializer, ProgramSerializer)
serializer.blockStart()
serializer.emitIndent()
serializer.appendLine(".valid = 0")
serializer.blockEnd(False)
def declareArray(self, serializer, identifier, size):
assert isinstance(serializer, ProgramSerializer)
serializer.appendFormat(
"struct {0} {1}[{2}]", self.name, identifier, size)
class EbpfMetadataType(EbpfStructType):
def __init__(self, hlirHeader, config):
super(EbpfMetadataType, self).__init__(hlirHeader, config)
def emitInitializer(self, serializer):
assert isinstance(serializer, ProgramSerializer)
serializer.blockStart()
for field in self.fields:
serializer.emitIndent()
serializer.appendFormat(".{0} = ", field.name)
field.type.emitInitializer(serializer)
serializer.append(",")
serializer.newline()
serializer.blockEnd(False)