1 # Copyright 2018 Vinci Consulting Corp. All Rights Reserved.
3 # Licensed under the Apache License, Version 2.0 (the "License"); you may
4 # not use this file except in compliance with the License. You may obtain
5 # a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 # License for the specific language governing permissions and limitations
19 class VppConfig(object):
20 stanzas = ['unix', 'api-trace', 'api-segment',
21 'socksvr', 'cpu', 'statseg', 'dpdk', 'plugins', 'tuntap',
23 kw = {'unix': ['interactive', 'nodaemon', 'log', 'full-coredump',
24 'coredump-size', 'cli-listen', 'runtime-dir', 'gid'],
25 'acl-plugin': ['connection hash buckets', 'connection hash memory',
26 'connection count max', 'main heap size',
27 'hash lookup heap size', 'hash lookup hash buckets',
28 'hash lookup hash memory', 'use tuple merge',
29 'tuple merge split threshold', 'reclassify sessions'],
30 'api-queue': ['len', 'length'],
31 'api-trace': ['on', 'enable, ''nitems', 'save-api-table'],
32 'api-segment': ['prefix', 'gid'],
33 'cj': ['on', 'records'],
34 'cpu': ['main-core', 'corelist-workers', 'skip-cores',
35 'workers', 'scheduler-policy', 'scheduler-priority'],
36 'dns': ['max-cache-size', 'max-ttl'],
37 'dpdk': ['dev', 'vdev', 'name', 'hqos', 'rss',
39 'num-mbufs', 'num-rx-queues', 'num-tx-queues',
40 'num-rx-desc', 'num-tx-desc',
41 'socket-mem', 'no-tx-checksum-offload', 'uio-driver',
42 'vlan-strip-offload', 'workers'],
43 # currently don't support dynamic keys
46 'l2tp': ['lookup-v6-src', 'lookup-v6-dst',
48 'nat': ['connection tracking', 'deterministic', 'dslite ce',
49 'endpoint-dependent', 'inside VRF id',
50 'max translations per user',
51 'nat64 bib hash bucket', 'nat64 bib hash memory',
52 'nat64 st hash buckets',
53 'outside ip6 VRF id', 'outside VRF id', 'out2in dpo'
54 'static mapping only',
55 'translation hash buckets',
56 'translation hash memory',
57 'user hash buckets', 'user hash memory',
59 'mactime': ['lookup-table-buckets', 'lookup-table-memory',
61 'mc': ['interface', 'no-delay', 'no-validate', 'max-delay',
62 'min-delay', 'n-bytes', 'n-packets',
65 'seed', 'window', 'verbose', ],
66 'oam': ['interval', 'misses-allowed'],
67 'plugins': ['path', 'plugin'],
69 'session': ['event-queue-length', 'preallocated-sessions',
70 'v4-session-table-buckets', 'v4-halfopen-table-buckets',
71 'v6-session-table-buckets', 'v6-halfopen-table-buckets',
72 'v6-halfopen-table-buckets'
74 'socksvr': ['default', 'socket-name'],
75 'statseg': ['socket-name'],
76 'tapcli': ['disable', 'mtu'],
77 'tcp': ['buffer-fail-fraction', 'cc-algo', 'max-rx-fifo',
78 'no-tx-pacing', 'preallocated-connections',
79 'preallocated-half-open-connections',
81 'tuntap': ['name', 'mtu', 'enable', 'disable',
83 'have-normal', 'have-normal-interface'
85 'vhost-user': ['coalesce-frames', 'coalesce-time',
90 default_values = {'unix': {'interactive': None,
95 self.values = type(self).default_values
98 def add(self, stanza, key, val):
99 if stanza not in type(self).stanzas:
100 raise ValueError("stanza '%s' must be in %s" %
101 (stanza, type(self).stanzas))
102 if key not in type(self).kw[stanza]:
103 raise ValueError("key '%s' must be in %s" %
104 (key, type(self).kw[stanza]))
105 self.values[stanza][key] = val
107 def add_plugin(self, key, val):
108 self.plugins.append((key, val,))
112 for stanza in type(self).stanzas:
114 if self.values[stanza]:
115 result = '%s\n%s {' % (result, stanza)
116 for key in type(self).kw[stanza]:
118 if key in self.values[stanza]:
119 result = '%s\n %s %s' % (
121 self.values[stanza][key]
122 if self.values[stanza][key] is not
125 # no key: nothing to do
127 if stanza == 'plugins' and key == 'plugin':
128 for plugin, val in self.plugins:
129 result = '%s\n plugin %s { % s }' % (
131 val if val is not None else '')
132 result = '%s\n}\n' % result
134 # no stanza not in self.values: nothing to do
139 return shlex.split(str(self))
142 class MinimalVppConfig(VppConfig):
143 default_values = {'unix': {'interactive': None,
144 'cli-listen': 'run/vpp/cli.sock',
150 class VppTestCaseVppConfig(VppConfig):
151 default_values = {'unix': {'nodaemon': None,
152 'full-coredump': None,
156 'api-trace': {'on': None},
162 # currently don't support dynamic keys
173 'socksvr': {'default': None},
182 class TestVppConfig(unittest.TestCase):
185 self.config = VppTestCaseVppConfig()
191 # reset default values for this test.
192 self.config.default_values['unix'] = {}
193 self.config.add('unix', 'coredump-size', size
194 if size is not None else 'unlimited')
195 self.assertIn('unix {\n coredump-size unlimited\n}\n',
198 self.config.add('unix', 'runtime-dir', tempdir)
199 self.assertIn('runtime-dir /tmp', str(self.config))
201 def test_api_segment(self):
202 shm_prefix = '/dev/shm'
203 self.config.add('api-segment', 'prefix', shm_prefix)
204 self.assertIn('api-segment {\n prefix /dev/shm\n}\n',
209 self.config.add('cpu', 'main-core', str(luc))
210 self.assertIn('cpu {\n main-core 0\n}\n', str(self.config))
212 def test_statseg(self):
213 stats_sock = '/stats.sock'
214 self.config.add('statseg', 'socket-name', stats_sock)
215 self.assertIn('statseg {\n socket-name /stats.sock\n}\n',
218 def test_plugin(self):
220 self.config.add('plugins', 'path', plugin_path)
221 self.assertIn('plugins {\n path /foo\n}\n',
224 self.config.add_plugin('dpdk_plugin.so', 'disable')
225 self.config.add_plugin('unittest_plugin.so', 'enable')
226 self.assertIn('plugin dpdk_plugin.so { disable }\n',
228 self.assertIn('plugin unittest_plugin.so { enable }\n',
232 if __name__ == '__main__':