BIER API and load-balancing fixes
[vpp.git] / test / vpp_bier.py
1 """
2   BIER Tables and Routes
3 """
4
5 import socket
6 from vpp_object import VppObject
7 from vpp_ip_route import MPLS_LABEL_INVALID, VppRoutePath, VppMplsLabel
8
9
10 class BIER_HDR_PAYLOAD:
11     BIER_HDR_PROTO_MPLS_DOWN_STREAM = 1
12     BIER_HDR_PROTO_MPLS_UP_STREAM = 2
13     BIER_HDR_PROTO_ETHERNET = 3
14     BIER_HDR_PROTO_IPV4 = 4
15     BIER_HDR_PROTO_IPV6 = 5
16     BIER_HDR_PROTO_VXLAN = 6
17     BIER_HDR_PROTO_CTRL = 7
18     BIER_HDR_PROTO_OAM = 8
19
20
21 class VppBierTableID():
22     def __init__(self, sub_domain_id, set_id, hdr_len_id):
23         self.set_id = set_id
24         self.sub_domain_id = sub_domain_id
25         self.hdr_len_id = hdr_len_id
26
27
28 def find_bier_table(test, bti):
29     tables = test.vapi.bier_table_dump()
30     for t in tables:
31         if bti.set_id == t.bt_tbl_id.bt_set \
32            and bti.sub_domain_id == t.bt_tbl_id.bt_sub_domain \
33            and bti.hdr_len_id == t.bt_tbl_id.bt_hdr_len_id:
34             return True
35     return False
36
37
38 def find_bier_route(test, bti, bp):
39     routes = test.vapi.bier_route_dump(bti)
40     for r in routes:
41         if bti.set_id == r.br_tbl_id.bt_set \
42            and bti.sub_domain_id == r.br_tbl_id.bt_sub_domain \
43            and bti.hdr_len_id == r.br_tbl_id.bt_hdr_len_id \
44            and bp == r.br_bp:
45             return True
46     return False
47
48
49 def find_bier_disp_table(test, bdti):
50     tables = test.vapi.bier_disp_table_dump()
51     for t in tables:
52         if bdti == t.bdt_tbl_id:
53             return True
54     return False
55
56
57 def find_bier_disp_entry(test, bdti, bp):
58     entries = test.vapi.bier_disp_entry_dump(bdti)
59     for e in entries:
60         if bp == e.bde_bp \
61            and bdti == e.bde_tbl_id:
62             return True
63     return False
64
65
66 def find_bier_imp(test, bti, bp):
67     imps = test.vapi.bier_imp_dump()
68     for i in imps:
69         if bti.set_id == i.bi_tbl_id.bt_set \
70            and bti.sub_domain_id == i.bi_tbl_id.bt_sub_domain \
71            and bti.hdr_len_id == i.bi_tbl_id.bt_hdr_len_id \
72            and bp == i.bi_src:
73             return True
74     return False
75
76
77 class VppBierTable(VppObject):
78     """
79     BIER Table
80     """
81
82     def __init__(self, test, id, mpls_label):
83         self._test = test
84         self.id = id
85         self.mpls_label = mpls_label
86
87     def add_vpp_config(self):
88         self._test.vapi.bier_table_add_del(
89             self.id,
90             self.mpls_label,
91             is_add=1)
92         self._test.registry.register(self, self._test.logger)
93
94     def remove_vpp_config(self):
95         self._test.vapi.bier_table_add_del(
96             self.id,
97             self.mpls_label,
98             is_add=0)
99
100     def __str__(self):
101         return self.object_id()
102
103     def object_id(self):
104         return "bier-table;[%d:%d:%d]" % (self.id.set_id,
105                                           self.id.sub_domain_id,
106                                           self.id.hdr_len_id)
107
108     def query_vpp_config(self):
109         return find_bier_table(self._test, self.id)
110
111
112 class VppBierRoute(VppObject):
113     """
114     BIER route
115     """
116
117     def __init__(self, test, tbl_id, bp, paths):
118         self._test = test
119         self.tbl_id = tbl_id
120         self.bp = bp
121         self.paths = paths
122
123     def encode_path(self, p):
124         lstack = []
125         for l in p.nh_labels:
126             if type(l) == VppMplsLabel:
127                 lstack.append(l.encode())
128             else:
129                 lstack.append({'label': l, 'ttl': 255})
130         n_labels = len(lstack)
131         while (len(lstack) < 16):
132             lstack.append({})
133         return {'next_hop': p.nh_addr,
134                 'weight': 1,
135                 'afi': p.proto,
136                 'sw_if_index': 0xffffffff,
137                 'preference': 0,
138                 'table_id': p.nh_table_id,
139                 'next_hop_id': p.next_hop_id,
140                 'is_udp_encap': p.is_udp_encap,
141                 'n_labels': n_labels,
142                 'label_stack': lstack}
143
144     def encode_paths(self):
145         br_paths = []
146         for p in self.paths:
147             br_paths.append(self.encode_path(p))
148         return br_paths
149
150     def add_vpp_config(self):
151         self._test.vapi.bier_route_add_del(
152             self.tbl_id,
153             self.bp,
154             self.encode_paths(),
155             is_add=1)
156         self._test.registry.register(self, self._test.logger)
157
158     def remove_vpp_config(self):
159         self._test.vapi.bier_route_add_del(
160             self.tbl_id,
161             self.bp,
162             self.encode_paths(),
163             is_add=0)
164
165     def update_paths(self, paths):
166         self.paths = paths
167         self._test.vapi.bier_route_add_del(
168             self.tbl_id,
169             self.bp,
170             self.encode_paths(),
171             is_replace=1)
172
173     def add_path(self, path):
174         self._test.vapi.bier_route_add_del(
175             self.tbl_id,
176             self.bp,
177             [self.encode_path(path)],
178             is_add=1,
179             is_replace=0)
180         self.paths.append(path)
181         self._test.registry.register(self, self._test.logger)
182
183     def remove_path(self, path):
184         self._test.vapi.bier_route_add_del(
185             self.tbl_id,
186             self.bp,
187             [self.encode_path(path)],
188             is_add=0,
189             is_replace=0)
190         self.paths.remove(path)
191
192     def remove_all_paths(self):
193         self._test.vapi.bier_route_add_del(
194             self.tbl_id,
195             self.bp,
196             [],
197             is_add=0,
198             is_replace=1)
199         self.paths = []
200
201     def __str__(self):
202         return self.object_id()
203
204     def object_id(self):
205         return "bier-route;[%d:%d:%d:%d]" % (self.tbl_id.set_id,
206                                              self.tbl_id.sub_domain_id,
207                                              self.tbl_id.hdr_len_id,
208                                              self.bp)
209
210     def query_vpp_config(self):
211         return find_bier_route(self._test, self.tbl_id, self.bp)
212
213
214 class VppBierImp(VppObject):
215     """
216     BIER route
217     """
218
219     def __init__(self, test, tbl_id, src, ibytes):
220         self._test = test
221         self.tbl_id = tbl_id
222         self.ibytes = ibytes
223         self.src = src
224
225     def add_vpp_config(self):
226         res = self._test.vapi.bier_imp_add(
227             self.tbl_id,
228             self.src,
229             self.ibytes)
230         self.bi_index = res.bi_index
231         self._test.registry.register(self, self._test.logger)
232
233     def remove_vpp_config(self):
234         self._test.vapi.bier_imp_del(
235             self.bi_index)
236
237     def __str__(self):
238         return self.object_id()
239
240     def object_id(self):
241         return "bier-imp;[%d:%d:%d:%d]" % (self.tbl_id.set_id,
242                                            self.tbl_id.sub_domain_id,
243                                            self.tbl_id.hdr_len_id,
244                                            self.src)
245
246     def query_vpp_config(self):
247         return find_bier_imp(self._test, self.tbl_id, self.src)
248
249
250 class VppBierDispTable(VppObject):
251     """
252     BIER Disposition Table
253     """
254
255     def __init__(self, test, id):
256         self._test = test
257         self.id = id
258
259     def add_vpp_config(self):
260         self._test.vapi.bier_disp_table_add_del(
261             self.id,
262             is_add=1)
263         self._test.registry.register(self, self._test.logger)
264
265     def remove_vpp_config(self):
266         self._test.vapi.bier_disp_table_add_del(
267             self.id,
268             is_add=0)
269
270     def __str__(self):
271         return self.object_id()
272
273     def object_id(self):
274         return "bier-disp-table;[%d]" % (self.id)
275
276     def query_vpp_config(self):
277         return find_bier_disp_table(self._test, self.id)
278
279
280 class VppBierDispEntry(VppObject):
281     """
282     BIER Disposition Entry
283     """
284
285     def __init__(self, test, tbl_id, bp, payload_proto, nh_proto,
286                  nh, nh_tbl, rpf_id=~0):
287         self._test = test
288         self.tbl_id = tbl_id
289         self.nh_tbl = nh_tbl
290         self.nh_proto = nh_proto
291         self.bp = bp
292         self.payload_proto = payload_proto
293         self.rpf_id = rpf_id
294         self.nh = socket.inet_pton(socket.AF_INET, nh)
295
296     def add_vpp_config(self):
297         self._test.vapi.bier_disp_entry_add_del(
298             self.tbl_id,
299             self.bp,
300             self.payload_proto,
301             self.nh_proto,
302             self.nh,
303             self.nh_tbl,
304             self.rpf_id,
305             is_add=1)
306         self._test.registry.register(self, self._test.logger)
307
308     def remove_vpp_config(self):
309         self._test.vapi.bier_disp_entry_add_del(
310             self.tbl_id,
311             self.bp,
312             self.payload_proto,
313             self.nh_proto,
314             self.nh,
315             self.nh_tbl,
316             self.rpf_id,
317             is_add=0)
318
319     def __str__(self):
320         return self.object_id()
321
322     def object_id(self):
323         return "bier-disp-entry;[%d:%d]" % (self.tbl_id,
324                                             self.bp)
325
326     def query_vpp_config(self):
327         return find_bier_disp_entry(self._test, self.tbl_id, self.bp)