# Copyright (c) Barefoot Networks, Inc. # Licensed under the Apache License, Version 2.0 (the "License") from p4_hlir.hlir import p4_counter, P4_DIRECT, P4_COUNTER_BYTES from programSerializer import ProgramSerializer from compilationException import * import ebpfTable import ebpfProgram class EbpfCounter(object): # noinspection PyUnresolvedReferences def __init__(self, hlircounter, program): assert isinstance(hlircounter, p4_counter) assert isinstance(program, ebpfProgram.EbpfProgram) self.name = hlircounter.name self.hlircounter = hlircounter width = hlircounter.min_width # ebpf counters only work on 64-bits if width <= 64: self.valueTypeName = program.config.uprefix + "64" else: raise NotSupportedException( "{0}: Counters with {1} bits", hlircounter, width) self.dataMapName = self.name if ((hlircounter.binding is None) or (hlircounter.binding[0] != P4_DIRECT)): raise NotSupportedException( "{0}: counter which is not direct", hlircounter) self.autoIncrement = (hlircounter.binding != None and hlircounter.binding[0] == P4_DIRECT) if hlircounter.type is P4_COUNTER_BYTES: self.increment = "{0}->len".format(program.packetName) else: self.increment = "1" def getSize(self, program): if self.hlircounter.instance_count is not None: return self.hlircounter.instance_count if self.autoIncrement: return self.getTable(program).size program.emitWarning( "{0} does not specify a max_size; using 1024", self.hlircounter) return 1024 def getTable(self, program): table = program.getTable(self.hlircounter.binding[1].name) assert isinstance(table, ebpfTable.EbpfTable) return table def serialize(self, serializer, program): assert isinstance(serializer, ProgramSerializer) # Direct counters have the same key as the associated table # Static counters have integer keys if self.autoIncrement: keyTypeName = "struct " + self.getTable(program).keyTypeName else: keyTypeName = program.config.uprefix + "32" program.config.serializeTableDeclaration( serializer, self.dataMapName, True, keyTypeName, self.valueTypeName, self.getSize(program)) def serializeCode(self, keyname, serializer, program): assert isinstance(serializer, ProgramSerializer) assert isinstance(program, ebpfProgram.EbpfProgram) serializer.emitIndent() serializer.appendFormat("/* Update counter {0} */", self.name) serializer.newline() valueName = "ctrvalue" initValuename = "init_val" serializer.emitIndent() serializer.appendFormat("{0} *{1};", self.valueTypeName, valueName) serializer.newline() serializer.emitIndent() serializer.appendFormat("{0} {1};", self.valueTypeName, initValuename) serializer.newline() serializer.emitIndent() serializer.appendLine("/* perform lookup */") serializer.emitIndent() program.config.serializeLookup( serializer, self.dataMapName, keyname, valueName) serializer.newline() serializer.emitIndent() serializer.appendFormat("if ({0} != NULL) ", valueName) serializer.newline() serializer.increaseIndent() serializer.emitIndent() serializer.appendFormat("__sync_fetch_and_add({0}, {1});", valueName, self.increment) serializer.newline() serializer.decreaseIndent() serializer.emitIndent() serializer.append("else ") serializer.blockStart() serializer.emitIndent() serializer.appendFormat("{0} = {1};", initValuename, self.increment) serializer.newline() serializer.emitIndent() program.config.serializeUpdate( serializer, self.dataMapName, keyname, initValuename) serializer.newline() serializer.blockEnd(True)