blob: 566ba4f68051befcc1dfadcb1f4b704346b48956 [file] [log] [blame]
Yi Tseng43ee7e82018-04-12 16:37:34 +08001#!/usr/bin/env python2.7
2# -*- utf-8 -*-
3import argparse
4import re
5import google.protobuf.text_format as tf
Yi Tseng13c27f12018-06-23 01:08:55 +08006from p4.config.v1 import p4info_pb2
Yi Tseng43ee7e82018-04-12 16:37:34 +08007
8
9copyright = '''/*
10 * Copyright 2017-present Open Networking Foundation
11 *
12 * Licensed under the Apache License, Version 2.0 (the "License");
13 * you may not use this file except in compliance with the License.
14 * You may obtain a copy of the License at
15 *
16 * http://www.apache.org/licenses/LICENSE-2.0
17 *
18 * Unless required by applicable law or agreed to in writing, software
19 * distributed under the License is distributed on an "AS IS" BASIS,
20 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21 * See the License for the specific language governing permissions and
22 * limitations under the License.
23 */
24'''
25
26imports = '''
27import org.onosproject.net.pi.model.PiActionId;
28import org.onosproject.net.pi.model.PiActionParamId;
29import org.onosproject.net.pi.model.PiActionProfileId;
30import org.onosproject.net.pi.model.PiControlMetadataId;
31import org.onosproject.net.pi.model.PiCounterId;
32import org.onosproject.net.pi.model.PiMatchFieldId;
33import org.onosproject.net.pi.model.PiTableId;'''
34
35PKG_FMT = 'package org.onosproject.pipelines.%s;'
36
37CLASS_OPEN = 'public final class %s {'
38CLASS_CLOSE = '}'
39
40DEFAULT_CONSTRUCTOR = '''
41 // hide default constructor
42 private %s() {
43 }
44'''
45
46CONST_FMT = ' public static final %s %s = %s;'
47SHORT_CONST_FMT =''' public static final %s %s =
48 %s;'''
49JAVA_STR = 'String'
50EMPTY_STR = ''
51JAVA_DOC_FMT = '''/**
52 * Constants for %s pipeline.
53 */'''
54
55
56PI_HF_FIELD_ID = 'PiMatchFieldId'
57PI_HF_FIELD_ID_CST = 'PiMatchFieldId.of("%s")'
58
59PI_TBL_ID = 'PiTableId'
60PI_TBL_ID_CST = 'PiTableId.of("%s")'
61
62PI_CTR_ID = 'PiCounterId'
63PI_CTR_ID_CST = 'PiCounterId.of("%s")'
64
65PI_ACT_ID = 'PiActionId'
66PI_ACT_ID_CST = 'PiActionId.of("%s")'
67
68PI_ACT_PRM_ID = 'PiActionParamId'
69PI_ACT_PRM_ID_CST = 'PiActionParamId.of("%s")'
70
71PI_ACT_PROF_ID = 'PiActionProfileId'
72PI_ACT_PROF_ID_CST = 'PiActionProfileId.of("%s")'
73
74PI_PKT_META_ID = 'PiControlMetadataId'
75PI_PKT_META_ID_CST = 'PiControlMetadataId.of("%s")'
76
77class ConstantClassGenerator(object):
78 headers = set()
79 header_fields = set()
80 tables = set()
81 counters = set()
82 direct_counters = set()
83 actions = set()
84 action_params = set()
85 action_profiles = set()
86 packet_metadata = set()
87
88 # https://stackoverflow.com/questions/1175208/elegant-python-function-to-convert-camelcase-to-snake-case
89 def convert_camel_to_all_caps(self, name):
90 s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name)
91 s1 = re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).upper()
92 return s1.replace('.', '_')
93
94 def __init__(self, base_name):
95
96 self.class_name = base_name.title() + 'Constants'
97 self.package_name = PKG_FMT % (base_name, )
98 self.java_doc = JAVA_DOC_FMT % (base_name, )
99
100 def parse(self, p4info):
101 for tbl in p4info.tables:
102 for mf in tbl.match_fields:
103 self.header_fields.add(mf.name)
104
105 self.tables.add(tbl.preamble.name)
106
107 for ctr in p4info.counters:
108 self.counters.add(ctr.preamble.name)
109
110 for dir_ctr in p4info.direct_counters:
111 self.direct_counters.add(dir_ctr.preamble.name)
112
113 for act in p4info.actions:
114 self.actions.add(act.preamble.name)
115
116 for param in act.params:
117 self.action_params.add(param.name)
118
119 for act_prof in p4info.action_profiles:
120 self.action_profiles.add(act_prof.preamble.name)
121
122 for cpm in p4info.controller_packet_metadata:
123 for mta in cpm.metadata:
124 self.packet_metadata.add(mta.name)
125
126 def const_line(self, name, type, constructor):
127 var_name = self.convert_camel_to_all_caps(name)
128 val = constructor % (name, )
129
130 line = CONST_FMT % (type, var_name, val)
131 if len(line) > 80:
132 line = SHORT_CONST_FMT % (type, var_name, val)
133 return line
134
135 def generate_java(self):
136 lines = list()
137 lines.append(copyright)
138 lines.append(self.package_name)
139 lines.append(imports)
140 lines.append(self.java_doc)
141 # generate the class
142 lines.append(CLASS_OPEN % (self.class_name, ))
143 lines.append(DEFAULT_CONSTRUCTOR % (self.class_name, ))
144
145 if len(self.header_fields) is not 0:
146 lines.append(' // Header field IDs')
147 for hf in self.header_fields:
148 lines.append(self.const_line(hf, PI_HF_FIELD_ID, PI_HF_FIELD_ID_CST))
149
150 if len(self.tables) is not 0:
151 lines.append(' // Table IDs')
152 for tbl in self.tables:
153 lines.append(self.const_line(tbl, PI_TBL_ID, PI_TBL_ID_CST))
154
155 if len(self.counters) is not 0:
156 lines.append(' // Indirect Counter IDs')
157 for ctr in self.counters:
158 lines.append(self.const_line(ctr, PI_CTR_ID, PI_CTR_ID_CST))
159
160 if len(self.direct_counters) is not 0:
161 lines.append(' // Direct Counter IDs')
162 for dctr in self.direct_counters:
163 lines.append(self.const_line(dctr, PI_CTR_ID, PI_CTR_ID_CST))
164
165 if len(self.actions) is not 0:
166 lines.append(' // Action IDs')
167 for act in self.actions:
168 lines.append(self.const_line(act, PI_ACT_ID, PI_ACT_ID_CST))
169
170 if len(self.action_params) is not 0:
171 lines.append(' // Action Param IDs')
172 for act_prm in self.action_params:
173 lines.append(self.const_line(act_prm, PI_ACT_PRM_ID, PI_ACT_PRM_ID_CST))
174
175 if len(self.action_profiles) is not 0:
176 lines.append(' // Action Profile IDs')
177 for act_prof in self.action_profiles:
178 lines.append(self.const_line(act_prof, PI_ACT_PROF_ID, PI_ACT_PROF_ID_CST))
179
180 if len(self.packet_metadata) is not 0:
181 lines.append(' // Packet Metadata IDs')
182 for pmeta in self.packet_metadata:
183 lines.append(self.const_line(pmeta, PI_PKT_META_ID, PI_PKT_META_ID_CST))
184 lines.append(CLASS_CLOSE)
185 # end of class
186
187 return '\n'.join(lines)
188
189
190def main():
191 parser = argparse.ArgumentParser(prog='onos-gen-p4-constants',
192 description='ONOS P4Info to Java constant generator.')
193 parser.add_argument('name', help='Name of the constant, will be used as class name')
194 parser.add_argument('p4info', help='P4Info file')
195 parser.add_argument('-o', '--output', help='output path', default='-')
196 args = parser.parse_args()
197
198 base_name = args.name
199 file_name = args.p4info
200 p4info = p4info_pb2.P4Info()
201 with open(file_name, 'r') as intput_file:
202 s = intput_file.read()
203 tf.Merge(s, p4info)
204
205 gen = ConstantClassGenerator(base_name)
206 gen.parse(p4info)
207
208 java_code = gen.generate_java()
209
210 if args.output == '-':
211 # std output
212 print java_code
213 else:
214 with open(args.output, 'w') as output_file:
215 output_file.write(java_code)
216
217
218if __name__ == '__main__':
219 main()