317fea7269a50592221dc73b4b09e098f5860917
[vpp.git] / src / vpp-api / python / vpp_papi / tests / test_vpp_serializer.py
1 #!/usr/bin/env python3
2
3 import unittest
4 from vpp_papi.vpp_serializer import VPPType, VPPEnumType
5 from vpp_papi.vpp_serializer import VPPUnionType, VPPMessage
6 from vpp_papi.vpp_serializer import VPPTypeAlias, VPPSerializerValueError
7 from vpp_papi import MACAddress
8 from socket import inet_pton, AF_INET, AF_INET6
9 import logging
10 import sys
11 from ipaddress import *
12
13
14 class TestLimits(unittest.TestCase):
15     def test_string(self):
16         fixed_string = VPPType('fixed_string',
17                                [['string', 'name', 16]])
18
19         b = fixed_string.pack({'name': 'foobar'})
20         self.assertEqual(len(b), 16)
21
22         # Ensure string is nul terminated
23         self.assertEqual(b.decode('ascii')[6], '\x00')
24
25         nt, size = fixed_string.unpack(b)
26         self.assertEqual(size, 16)
27         self.assertEqual(nt.name, 'foobar')
28
29         # Empty string
30         b = fixed_string.pack({'name': ''})
31         self.assertEqual(len(b), 16)
32         nt, size = fixed_string.unpack(b)
33         self.assertEqual(size, 16)
34         self.assertEqual(nt.name, '')
35
36         # String too long
37         with self.assertRaises(VPPSerializerValueError):
38             b = fixed_string.pack({'name': 'foobarfoobar1234'})
39
40         variable_string = VPPType('variable_string',
41                                   [['string', 'name', 0]])
42         b = variable_string.pack({'name': 'foobar'})
43         self.assertEqual(len(b), 4 + len('foobar'))
44
45         nt, size = variable_string.unpack(b)
46         self.assertEqual(size, 4 + len('foobar'))
47         self.assertEqual(nt.name, 'foobar')
48         self.assertEqual(len(nt.name), len('foobar'))
49
50
51     def test_limit(self):
52         limited_type = VPPType('limited_type_t',
53                                [['string', 'name', 0, {'limit': 16}]])
54         unlimited_type = VPPType('limited_type_t',
55                                  [['string', 'name', 0]])
56
57         b = limited_type.pack({'name': 'foobar'})
58         self.assertEqual(len(b), 10)
59         b = unlimited_type.pack({'name': 'foobar'})
60         self.assertEqual(len(b), 10)
61
62         with self.assertRaises(VPPSerializerValueError):
63             b = limited_type.pack({'name': 'foobar'*3})
64
65
66 class TestDefaults(unittest.TestCase):
67     def test_defaults(self):
68         default_type = VPPType('default_type_t',
69                                [['u16', 'mtu', {'default': 1500, 'limit': 0}]])
70         without_default_type = VPPType('without_default_type_t',
71                                        [['u16', 'mtu']])
72
73         b = default_type.pack({})
74         self.assertEqual(len(b), 2)
75         nt, size = default_type.unpack(b)
76         self.assertEqual(len(b), size)
77         self.assertEqual(nt.mtu, 1500)
78
79         # distinguish between parameter 0 and parameter not passed
80         b = default_type.pack({'mtu': 0})
81         self.assertEqual(len(b), 2)
82         nt, size = default_type.unpack(b)
83         self.assertEqual(len(b), size)
84         self.assertEqual(nt.mtu, 0)
85
86         # Ensure that basetypes does not inherit default
87         b = without_default_type.pack({})
88         self.assertEqual(len(b), 2)
89         nt, size = default_type.unpack(b)
90         self.assertEqual(len(b), size)
91         self.assertEqual(nt.mtu, 0)
92
93         # default enum type
94         VPPEnumType('vl_api_enum_t', [["ADDRESS_IP4", 0],
95                                       ["ADDRESS_IP6", 1],
96                                       {"enumtype": "u32"}])
97
98         default_with_enum = VPPType('default_enum_type_t',
99                                     [['u16', 'mtu'], ['vl_api_enum_t',
100                                                       'e', {'default': 1}]])
101
102         b = default_with_enum.pack({})
103         self.assertEqual(len(b), 6)
104         nt, size = default_with_enum.unpack(b)
105         self.assertEqual(len(b), size)
106         self.assertEqual(nt.e, 1)
107
108 class TestAddType(unittest.TestCase):
109
110     def test_union(self):
111         un = VPPUnionType('test_union',
112                           [['u8', 'is_bool'],
113                            ['u32', 'is_int']])
114
115         b = un.pack({'is_int': 0x12345678})
116         nt, size = un.unpack(b)
117         self.assertEqual(len(b), size)
118         self.assertEqual(nt.is_bool, 0x12)
119         self.assertEqual(nt.is_int, 0x12345678)
120
121     def test_address(self):
122         af = VPPEnumType('vl_api_address_family_t', [["ADDRESS_IP4", 0],
123                                                      ["ADDRESS_IP6", 1],
124                                                      {"enumtype": "u32"}])
125         ip4 = VPPTypeAlias('vl_api_ip4_address_t', {'type': 'u8',
126                                                     'length': 4})
127         ip6 = VPPTypeAlias('vl_api_ip6_address_t', {'type': 'u8',
128                                                     'length': 16})
129         VPPUnionType('vl_api_address_union_t',
130                      [["vl_api_ip4_address_t", "ip4"],
131                       ["vl_api_ip6_address_t", "ip6"]])
132
133         address = VPPType('vl_api_address_t',
134                           [['vl_api_address_family_t', 'af'],
135                            ['vl_api_address_union_t', 'un']])
136
137         prefix = VPPType('vl_api_prefix_t',
138                          [['vl_api_address_t', 'address'],
139                           ['u8', 'len']])
140
141         va_address_list = VPPType('list_addresses',
142                                   [['u8', 'count'],
143                                    ['vl_api_address_t', 'addresses',
144                                     0, 'count']])
145
146         message_with_va_address_list = VPPType('msg_with_vla',
147                                                [['list_addresses',
148                                                  'vla_address'],
149                                                 ['u8', 'is_cool']])
150
151         b = ip4.pack(inet_pton(AF_INET, '1.1.1.1'))
152         self.assertEqual(len(b), 4)
153         nt, size = ip4.unpack(b)
154         self.assertEqual(str(nt), '1.1.1.1')
155
156         b = ip6.pack(inet_pton(AF_INET6, '1::1'))
157         self.assertEqual(len(b), 16)
158
159         b = address.pack({'af': af.ADDRESS_IP4,
160                           'un':
161                           {'ip4': inet_pton(AF_INET, '2.2.2.2')}})
162         self.assertEqual(len(b), 20)
163
164         nt, size = address.unpack(b)
165         self.assertEqual(str(nt), '2.2.2.2')
166
167         # List of addresses
168         address_list = []
169         for i in range(4):
170             address_list.append({'af': af.ADDRESS_IP4,
171                                  'un':
172                                  {'ip4': inet_pton(AF_INET, '2.2.2.2')}})
173         b = va_address_list.pack({'count': len(address_list),
174                                   'addresses': address_list})
175         self.assertEqual(len(b), 81)
176
177         nt, size = va_address_list.unpack(b)
178         self.assertEqual(str(nt.addresses[0]), '2.2.2.2')
179
180         b = message_with_va_address_list.pack({'vla_address':
181                                                {'count': len(address_list),
182                                                 'addresses': address_list},
183                                                'is_cool': 100})
184         self.assertEqual(len(b), 82)
185         nt, size = message_with_va_address_list.unpack(b)
186         self.assertEqual(nt.is_cool, 100)
187
188     def test_address_with_prefix(self):
189         af = VPPEnumType('vl_api_address_family_t', [["ADDRESS_IP4", 0],
190                                                      ["ADDRESS_IP6", 1],
191                                                      {"enumtype": "u32"}])
192         ip4 = VPPTypeAlias('vl_api_ip4_address_t', {'type': 'u8',
193                                                     'length': 4})
194         ip6 = VPPTypeAlias('vl_api_ip6_address_t', {'type': 'u8',
195                                                     'length': 16})
196         VPPUnionType('vl_api_address_union_t',
197                      [["vl_api_ip4_address_t", "ip4"],
198                       ["vl_api_ip6_address_t", "ip6"]])
199
200         address = VPPType('vl_api_address_t',
201                           [['vl_api_address_family_t', 'af'],
202                            ['vl_api_address_union_t', 'un']])
203
204
205         prefix = VPPType('vl_api_prefix_t',
206                          [['vl_api_address_t', 'address'],
207                           ['u8', 'len']])
208         prefix4 = VPPType('vl_api_ip4_prefix_t',
209                           [['vl_api_ip4_address_t', 'address'],
210                           ['u8', 'len']])
211         prefix6 = VPPType('vl_api_ip6_prefix_t',
212                           [['vl_api_ip6_address_t', 'address'],
213                           ['u8', 'len']])
214
215         address_with_prefix = VPPTypeAlias('vl_api_address_with_prefix_t', {'type': 'vl_api_prefix_t' })
216         address4_with_prefix = VPPTypeAlias('vl_api_ip4_address_with_prefix_t',
217                                             {'type': 'vl_api_ip4_prefix_t' })
218         address6_with_prefix = VPPTypeAlias('vl_api_ip6_address_with_prefix_t',
219                                             {'type': 'vl_api_ip6_prefix_t' })
220
221         awp_type = VPPType('foobar_t',
222                            [['vl_api_address_with_prefix_t', 'address']])
223
224         # address with prefix
225         b = address_with_prefix.pack(IPv4Interface('2.2.2.2/24'))
226         self.assertEqual(len(b), 21)
227         nt, size = address_with_prefix.unpack(b)
228         self.assertTrue(isinstance(nt, IPv4Interface))
229         self.assertEqual(str(nt), '2.2.2.2/24')
230
231         b = address_with_prefix.pack(IPv6Interface('2::2/64'))
232         self.assertEqual(len(b), 21)
233         nt, size = address_with_prefix.unpack(b)
234         self.assertTrue(isinstance(nt, IPv6Interface))
235         self.assertEqual(str(nt), '2::2/64')
236
237         b = address_with_prefix.pack(IPv4Network('2.2.2.2/24', strict=False))
238         self.assertEqual(len(b), 21)
239         nt, size = address_with_prefix.unpack(b)
240         self.assertTrue(isinstance(nt, IPv4Interface))
241         self.assertEqual(str(nt), '2.2.2.0/24')
242
243         b = address4_with_prefix.pack('2.2.2.2/24')
244         self.assertEqual(len(b), 5)
245         nt, size = address4_with_prefix.unpack(b)
246         self.assertTrue(isinstance(nt, IPv4Interface))
247         self.assertEqual(str(nt), '2.2.2.2/24')
248         b = address4_with_prefix.pack(IPv4Interface('2.2.2.2/24'))
249         self.assertEqual(len(b), 5)
250
251         b = address6_with_prefix.pack('2::2/64')
252         self.assertEqual(len(b), 17)
253         nt, size = address6_with_prefix.unpack(b)
254         self.assertTrue(isinstance(nt, IPv6Interface))
255         self.assertEqual(str(nt), '2::2/64')
256         b = address6_with_prefix.pack(IPv6Interface('2::2/64'))
257         self.assertEqual(len(b), 17)
258
259         b = prefix.pack('192.168.10.0/24')
260         self.assertEqual(len(b), 21)
261         nt, size = prefix.unpack(b)
262         self.assertTrue(isinstance(nt, IPv4Network))
263         self.assertEqual(str(nt), '192.168.10.0/24')
264
265         b = awp_type.pack({'address': '1.2.3.4/24'})
266         self.assertEqual(len(b), 21)
267         nt, size = awp_type.unpack(b)
268         self.assertTrue(isinstance(nt.address, IPv4Interface))
269         self.assertEqual(str(nt.address), '1.2.3.4/24')
270
271         b = awp_type.pack({'address': IPv4Interface('1.2.3.4/24')})
272         self.assertEqual(len(b), 21)
273         nt, size = awp_type.unpack(b)
274         self.assertTrue(isinstance(nt.address, IPv4Interface))
275         self.assertEqual(str(nt.address), '1.2.3.4/24')
276
277
278     def test_recursive_address(self):
279         af = VPPEnumType('vl_api_address_family_t', [["ADDRESS_IP4", 0],
280                                                      ["ADDRESS_IP6", 1],
281                                                      {"enumtype": "u32"}])
282         ip4 = VPPTypeAlias('vl_api_ip4_address_t', {'type': 'u8',
283                                                     'length': 4})
284         b = ip4.pack('1.1.1.1')
285         self.assertEqual(len(b), 4)
286         nt, size = ip4.unpack(b)
287
288         self.assertEqual(str(nt), '1.1.1.1')
289
290         ip6 = VPPTypeAlias('vl_api_ip6_address_t', {'type': 'u8',
291                                                     'length': 16})
292         VPPUnionType('vl_api_address_union_t',
293                      [["vl_api_ip4_address_t", "ip4"],
294                       ["vl_api_ip6_address_t", "ip6"]])
295
296         address = VPPType('vl_api_address_t',
297                           [['vl_api_address_family_t', 'af'],
298                            ['vl_api_address_union_t', 'un']])
299
300         prefix = VPPType('vl_api_prefix_t',
301                          [['vl_api_address_t', 'address'],
302                           ['u8', 'len']])
303         message = VPPMessage('svs',
304                              [['vl_api_prefix_t', 'prefix']])
305         message_addr = VPPMessage('svs_address',
306                                   [['vl_api_address_t', 'address']])
307
308         b = message_addr.pack({'address': "1::1"})
309         self.assertEqual(len(b), 20)
310         nt, size = message_addr.unpack(b)
311         self.assertEqual("1::1", str(nt.address))
312         b = message_addr.pack({'address': "1.1.1.1"})
313         self.assertEqual(len(b), 20)
314         nt, size = message_addr.unpack(b)
315         self.assertEqual("1.1.1.1", str(nt.address))
316
317         b = message.pack({'prefix': "1.1.1.0/24"})
318         self.assertEqual(len(b), 21)
319         nt, size = message.unpack(b)
320         self.assertEqual("1.1.1.0/24", str(nt.prefix))
321
322         message_array = VPPMessage('address_array',
323                                    [['vl_api_ip6_address_t',
324                                      'addresses', 2]])
325         b = message_array.pack({'addresses': [IPv6Address(u"1::1"), "2::2"]})
326         self.assertEqual(len(b), 32)
327         message_array_vla = VPPMessage('address_array_vla',
328                                        [['u32', 'num'],
329                                         ['vl_api_ip6_address_t',
330                                          'addresses', 0, 'num']])
331         b = message_array_vla.pack({'addresses': ["1::1", "2::2"], 'num': 2})
332         self.assertEqual(len(b), 36)
333
334         message_array4 = VPPMessage('address_array4',
335                                     [['vl_api_ip4_address_t',
336                                       'addresses', 2]])
337         b = message_array4.pack({'addresses': ["1.1.1.1", "2.2.2.2"]})
338         self.assertEqual(len(b), 8)
339         b = message_array4.pack({'addresses': [IPv4Address(u"1.1.1.1"),
340                                                "2.2.2.2"]})
341         self.assertEqual(len(b), 8)
342
343         message = VPPMessage('address', [['vl_api_address_t', 'address']])
344         b = message.pack({'address': '1::1'})
345         self.assertEqual(len(b), 20)
346         b = message.pack({'address': '1.1.1.1'})
347         self.assertEqual(len(b), 20)
348         message = VPPMessage('prefix', [['vl_api_prefix_t', 'prefix']])
349         b = message.pack({'prefix': '1::1/130'})
350         self.assertEqual(len(b), 21)
351         b = message.pack({'prefix': IPv6Network(u'1::/119')})
352         self.assertEqual(len(b), 21)
353         b = message.pack({'prefix': IPv4Network(u'1.1.0.0/16')})
354         self.assertEqual(len(b), 21)
355
356     def test_zero_vla(self):
357         '''Default zero'ed out for VLAs'''
358         list = VPPType('vl_api_list_t',
359                        [['u8', 'count', 10]])
360
361         # Define an embedded VLA type
362         valist = VPPType('vl_api_valist_t',
363                          [['u8', 'count'],
364                           ['u8', 'string', 0, 'count']])
365         # Define a message
366         vamessage = VPPMessage('vamsg',
367                                [['vl_api_valist_t', 'valist'],
368                                 ['u8', 'is_something']])
369
370         message = VPPMessage('msg',
371                              [['vl_api_list_t', 'list'],
372                               ['u8', 'is_something']])
373
374         # Pack message without VLA specified
375         b = message.pack({'is_something': 1})
376         b = vamessage.pack({'is_something': 1})
377
378     def test_arrays(self):
379         # Test cases
380         # 1. Fixed list
381         # 2. Fixed list of variable length sub type
382         # 3. Variable length type
383         #
384         s = VPPType('str', [['u32', 'length'],
385                             ['u8', 'string', 0, 'length']])
386
387         ip4 = VPPType('ip4_address', [['u8', 'address', 4]])
388         listip4 = VPPType('list_ip4_t', [['ip4_address', 'addresses', 4]])
389         valistip4 = VPPType('list_ip4_t',
390                             [['u8', 'count'],
391                              ['ip4_address', 'addresses', 0, 'count']])
392
393         valistip4_legacy = VPPType('list_ip4_t',
394                                    [['u8', 'foo'],
395                                     ['ip4_address', 'addresses', 0]])
396
397         addresses = []
398         for i in range(4):
399             addresses.append({'address': inet_pton(AF_INET, '2.2.2.2')})
400         b = listip4.pack({'addresses': addresses})
401         self.assertEqual(len(b), 16)
402         nt, size = listip4.unpack(b)
403         self.assertEqual(nt.addresses[0].address,
404                          inet_pton(AF_INET, '2.2.2.2'))
405
406         b = valistip4.pack({'count': len(addresses), 'addresses': addresses})
407         self.assertEqual(len(b), 17)
408
409         nt, size = valistip4.unpack(b)
410         self.assertEqual(nt.count, 4)
411         self.assertEqual(nt.addresses[0].address,
412                          inet_pton(AF_INET, '2.2.2.2'))
413
414         b = valistip4_legacy.pack({'foo': 1, 'addresses': addresses})
415         self.assertEqual(len(b), 17)
416         nt, size = valistip4_legacy.unpack(b)
417         self.assertEqual(len(nt.addresses), 4)
418         self.assertEqual(nt.addresses[0].address,
419                          inet_pton(AF_INET, '2.2.2.2'))
420
421         string = 'foobar foobar'
422         b = s.pack({'length': len(string), 'string': string.encode('utf-8')})
423         nt, size = s.unpack(b)
424         self.assertEqual(len(b), size)
425
426     def test_string(self):
427         s = VPPType('str', [['u32', 'length'],
428                             ['u8', 'string', 0, 'length']])
429
430         string = ''
431         b = s.pack({'length': len(string), 'string': string.encode('utf-8')})
432         nt, size = s.unpack(b)
433         self.assertEqual(len(b), size)
434
435     def test_message(self):
436         foo = VPPMessage('foo', [['u16', '_vl_msg_id'],
437                                  ['u8', 'client_index'],
438                                  ['u8', 'something'],
439                                  {"crc": "0x559b9f3c"}])
440         b = foo.pack({'_vl_msg_id': 1, 'client_index': 5,
441                       'something': 200})
442         nt, size = foo.unpack(b)
443         self.assertEqual(len(b), size)
444         self.assertEqual(nt.something, 200)
445
446     def test_abf(self):
447
448         fib_mpls_label = VPPType('vl_api_fib_mpls_label_t',
449                                  [['u8', 'is_uniform'],
450                                   ['u32', 'label'],
451                                   ['u8', 'ttl'],
452                                   ['u8', 'exp']])
453
454         label_stack = {'is_uniform': 0,
455                        'label': 0,
456                        'ttl': 0,
457                        'exp': 0}
458
459         b = fib_mpls_label.pack(label_stack)
460         self.assertEqual(len(b), 7)
461
462         fib_path = VPPType('vl_api_fib_path_t',
463                            [['u32', 'sw_if_index'],
464                             ['u32', 'table_id'],
465                             ['u8', 'weight'],
466                             ['u8', 'preference'],
467                             ['u8', 'is_local'],
468                             ['u8', 'is_drop'],
469                             ['u8', 'is_udp_encap'],
470                             ['u8', 'is_unreach'],
471                             ['u8', 'is_prohibit'],
472                             ['u8', 'is_resolve_host'],
473                             ['u8', 'is_resolve_attached'],
474                             ['u8', 'is_dvr'],
475                             ['u8', 'is_source_lookup'],
476                             ['u8', 'afi'],
477                             ['u8', 'next_hop', 16],
478                             ['u32', 'next_hop_id'],
479                             ['u32', 'rpf_id'],
480                             ['u32', 'via_label'],
481                             ['u8', 'n_labels'],
482                             ['vl_api_fib_mpls_label_t', 'label_stack', 16]])
483         label_stack_list = []
484         for i in range(16):
485             label_stack_list.append(label_stack)
486
487         paths = {'is_udp_encap': 0,
488                  'next_hop': b'\x10\x02\x02\xac',
489                  'table_id': 0,
490                  'afi': 0,
491                  'weight': 1,
492                  'next_hop_id': 4294967295,
493                  'label_stack': label_stack_list,
494                  'n_labels': 0,
495                  'sw_if_index': 4294967295,
496                  'preference': 0}
497
498         b = fib_path.pack(paths)
499         self.assertEqual(len(b), (7*16) + 49)
500
501         abf_policy = VPPType('vl_api_abf_policy_t',
502                              [['u32', 'policy_id'],
503                               ['u32', 'acl_index'],
504                               ['u8', 'n_paths'],
505                               ['vl_api_fib_path_t', 'paths', 0, 'n_paths']])
506
507         policy = {
508             'n_paths': 1,
509             'paths': [paths],
510             'acl_index': 0,
511             'policy_id': 10}
512
513         b = abf_policy.pack(policy)
514         self.assertEqual(len(b), (7*16) + 49 + 9)
515
516         abf_policy_add_del = VPPMessage('abf_policy_add_del',
517                                         [['u16', '_vl_msg_id'],
518                                          ['u32', 'client_index'],
519                                          ['u32', 'context'],
520                                          ['u8', 'is_add'],
521                                          ['vl_api_abf_policy_t', 'policy']])
522
523         b = abf_policy_add_del.pack({'is_add': 1,
524                                      'context': 66,
525                                      '_vl_msg_id': 1066,
526                                      'policy': policy})
527
528         nt, size = abf_policy_add_del.unpack(b)
529         self.assertEqual(nt.policy.paths[0].next_hop,
530                          b'\x10\x02\x02\xac\x00\x00\x00\x00'
531                          b'\x00\x00\x00\x00\x00\x00\x00\x00')
532
533     def test_bier(self):
534
535         bier_table_id = VPPType('vl_api_bier_table_id_t',
536                                 [['u8', 'bt_set'],
537                                  ['u8', 'bt_sub_domain'],
538                                  ['u8', 'bt_hdr_len_id']])
539
540         bier_imp_add = VPPMessage('bier_imp_add',
541                                   [['u32', 'client_index'],
542                                    ['u32', 'context'],
543                                    ['vl_api_bier_table_id_t', 'bi_tbl_id'],
544                                    ['u16', 'bi_src'],
545                                    ['u8', 'bi_n_bytes'],
546                                    ['u8', 'bi_bytes', 0, 'bi_n_bytes']])
547
548         table_id = {'bt_set': 0,
549                     'bt_sub_domain': 0,
550                     'bt_hdr_len_id': 0}
551
552         bibytes = b'foobar'
553
554         b = bier_imp_add.pack({'bi_tbl_id': table_id,
555                                'bi_n_bytes': len(bibytes),
556                                'bi_bytes': bibytes})
557
558         self.assertEqual(len(b), 20)
559
560
561     def test_lisp(self):
562         VPPEnumType('vl_api_eid_type_t',
563                     [["EID_TYPE_API_PREFIX", 0],
564                      ["EID_TYPE_API_MAC", 1],
565                      ["EID_TYPE_API_NSH", 2],
566                      {"enumtype": "u32"}])
567
568         VPPTypeAlias('vl_api_mac_address_t', {'type': 'u8',
569                                               'length': 6})
570
571         VPPType('vl_api_nsh_t',
572                 [["u32", "spi"],
573                  ["u8", "si"]])
574
575         VPPEnumType('vl_api_address_family_t', [["ADDRESS_IP4", 0],
576                                                 ["ADDRESS_IP6", 1],
577                                                 {"enumtype": "u32"}])
578         VPPTypeAlias('vl_api_ip4_address_t', {'type': 'u8',
579                                               'length': 4})
580         VPPTypeAlias('vl_api_ip6_address_t', {'type': 'u8',
581                                               'length': 16})
582         VPPUnionType('vl_api_address_union_t',
583                      [["vl_api_ip4_address_t", "ip4"],
584                       ["vl_api_ip6_address_t", "ip6"]])
585
586         VPPType('vl_api_address_t',
587                 [['vl_api_address_family_t', 'af'],
588                  ['vl_api_address_union_t', 'un']])
589
590         VPPType('vl_api_prefix_t',
591                 [['vl_api_address_t', 'address'],
592                  ['u8', 'len']])
593
594         VPPUnionType('vl_api_eid_address_t',
595                      [["vl_api_prefix_t", "prefix"],
596                       ["vl_api_mac_address_t", "mac"],
597                       ["vl_api_nsh_t", "nsh"]])
598
599         eid = VPPType('vl_api_eid_t',
600                       [["vl_api_eid_type_t", "type"],
601                        ["vl_api_eid_address_t", "address"]])
602
603         b = eid.pack({'type':1,
604                       'address': {
605                           'mac': MACAddress('aa:bb:cc:dd:ee:ff')}})
606         self.assertEqual(len(b), 25)
607         nt, size = eid.unpack(b)
608         self.assertEqual(str(nt.address.mac), 'aa:bb:cc:dd:ee:ff')
609         self.assertIsNone(nt.address.prefix)
610
611
612 if __name__ == '__main__':
613     unittest.main()