• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright (c) Barefoot Networks, Inc.
2# Licensed under the Apache License, Version 2.0 (the "License")
3
4from p4_hlir.hlir import p4_counter, P4_DIRECT, P4_COUNTER_BYTES
5from programSerializer import ProgramSerializer
6from compilationException import *
7import ebpfTable
8import ebpfProgram
9
10
11class EbpfCounter(object):
12    # noinspection PyUnresolvedReferences
13    def __init__(self, hlircounter, program):
14        assert isinstance(hlircounter, p4_counter)
15        assert isinstance(program, ebpfProgram.EbpfProgram)
16
17        self.name = hlircounter.name
18        self.hlircounter = hlircounter
19
20        width = hlircounter.min_width
21        # ebpf counters only work on 64-bits
22        if width <= 64:
23            self.valueTypeName = program.config.uprefix + "64"
24        else:
25            raise NotSupportedException(
26                "{0}: Counters with {1} bits", hlircounter, width)
27
28        self.dataMapName = self.name
29
30        if ((hlircounter.binding is None) or
31            (hlircounter.binding[0] != P4_DIRECT)):
32            raise NotSupportedException(
33                "{0}: counter which is not direct", hlircounter)
34
35        self.autoIncrement = (hlircounter.binding != None and
36                              hlircounter.binding[0] == P4_DIRECT)
37
38        if hlircounter.type is P4_COUNTER_BYTES:
39            self.increment = "{0}->len".format(program.packetName)
40        else:
41            self.increment = "1"
42
43    def getSize(self, program):
44        if self.hlircounter.instance_count is not None:
45            return self.hlircounter.instance_count
46        if self.autoIncrement:
47            return self.getTable(program).size
48        program.emitWarning(
49            "{0} does not specify a max_size; using 1024", self.hlircounter)
50        return 1024
51
52    def getTable(self, program):
53        table = program.getTable(self.hlircounter.binding[1].name)
54        assert isinstance(table, ebpfTable.EbpfTable)
55        return table
56
57    def serialize(self, serializer, program):
58        assert isinstance(serializer, ProgramSerializer)
59
60        # Direct counters have the same key as the associated table
61        # Static counters have integer keys
62        if self.autoIncrement:
63            keyTypeName = "struct " + self.getTable(program).keyTypeName
64        else:
65            keyTypeName = program.config.uprefix + "32"
66        program.config.serializeTableDeclaration(
67            serializer, self.dataMapName, True, keyTypeName,
68            self.valueTypeName, self.getSize(program))
69
70    def serializeCode(self, keyname, serializer, program):
71        assert isinstance(serializer, ProgramSerializer)
72        assert isinstance(program, ebpfProgram.EbpfProgram)
73
74        serializer.emitIndent()
75        serializer.appendFormat("/* Update counter {0} */", self.name)
76        serializer.newline()
77
78        valueName = "ctrvalue"
79        initValuename = "init_val"
80
81        serializer.emitIndent()
82        serializer.appendFormat("{0} *{1};", self.valueTypeName, valueName)
83        serializer.newline()
84        serializer.emitIndent()
85        serializer.appendFormat("{0} {1};", self.valueTypeName, initValuename)
86        serializer.newline()
87
88        serializer.emitIndent()
89        serializer.appendLine("/* perform lookup */")
90        serializer.emitIndent()
91        program.config.serializeLookup(
92            serializer, self.dataMapName, keyname, valueName)
93        serializer.newline()
94
95        serializer.emitIndent()
96        serializer.appendFormat("if ({0} != NULL) ", valueName)
97        serializer.newline()
98        serializer.increaseIndent()
99        serializer.emitIndent()
100        serializer.appendFormat("__sync_fetch_and_add({0}, {1});",
101                                valueName, self.increment)
102        serializer.newline()
103        serializer.decreaseIndent()
104        serializer.emitIndent()
105
106        serializer.append("else ")
107        serializer.blockStart()
108        serializer.emitIndent()
109        serializer.appendFormat("{0} = {1};", initValuename, self.increment)
110        serializer.newline()
111
112        serializer.emitIndent()
113        program.config.serializeUpdate(
114            serializer, self.dataMapName, keyname, initValuename)
115        serializer.newline()
116        serializer.blockEnd(True)
117