BFD: IPv6 support
[vpp.git] / test / bfd.py
1 from socket import AF_INET, AF_INET6
2 from scapy.all import *
3 from scapy.packet import *
4 from scapy.fields import *
5 from framework import *
6 from vpp_object import *
7 from util import NumericConstant
8
9
10 class BFDDiagCode(NumericConstant):
11     """ BFD Diagnostic Code """
12     no_diagnostic = 0
13     control_detection_time_expired = 1
14     echo_function_failed = 2
15     neighbor_signaled_session_down = 3
16     forwarding_plane_reset = 4
17     path_down = 5
18     concatenated_path_down = 6
19     administratively_down = 7
20     reverse_concatenated_path_down = 8
21
22     desc_dict = {
23         no_diagnostic: "No diagnostic",
24         control_detection_time_expired: "Control Detection Time Expired",
25         echo_function_failed: "Echo Function Failed",
26         neighbor_signaled_session_down: "Neighbor Signaled Session Down",
27         forwarding_plane_reset: "Forwarding Plane Reset",
28         path_down: "Path Down",
29         concatenated_path_down: "Concatenated Path Down",
30         administratively_down: "Administratively Down",
31         reverse_concatenated_path_down: "Reverse Concatenated Path Down",
32     }
33
34     def __init__(self, value):
35         NumericConstant.__init__(self, value)
36
37
38 class BFDState(NumericConstant):
39     """ BFD State """
40     admin_down = 0
41     down = 1
42     init = 2
43     up = 3
44
45     desc_dict = {
46         admin_down: "AdminDown",
47         down: "Down",
48         init: "Init",
49         up: "Up",
50     }
51
52     def __init__(self, value):
53         NumericConstant.__init__(self, value)
54
55
56 class BFD(Packet):
57
58     udp_dport = 3784  #: BFD destination port per RFC 5881
59     udp_sport_min = 49152  #: BFD source port min value per RFC 5881
60     udp_sport_max = 65535  #: BFD source port max value per RFC 5881
61
62     name = "BFD"
63
64     fields_desc = [
65         BitField("version", 1, 3),
66         BitEnumField("diag", 0, 5, BFDDiagCode.desc_dict),
67         BitEnumField("state", 0, 2, BFDState.desc_dict),
68         FlagsField("flags", 0, 6, ['P', 'F', 'C', 'A', 'D', 'M']),
69         XByteField("detect_mult", 0),
70         XByteField("length", 24),
71         BitField("my_discriminator", 0, 32),
72         BitField("your_discriminator", 0, 32),
73         BitField("desired_min_tx_interval", 0, 32),
74         BitField("required_min_rx_interval", 0, 32),
75         BitField("required_min_echo_rx_interval", 0, 32)]
76
77     def mysummary(self):
78         return self.sprintf("BFD(my_disc=%BFD.my_discriminator%,"
79                             "your_disc=%BFD.your_discriminator%)")
80
81 # glue the BFD packet class to scapy parser
82 bind_layers(UDP, BFD, dport=BFD.udp_dport)
83
84
85 class VppBFDUDPSession(VppObject):
86     """ Represents BFD UDP session in VPP """
87
88     @property
89     def test(self):
90         """ Test which created this session """
91         return self._test
92
93     @property
94     def interface(self):
95         """ Interface on which this session lives """
96         return self._interface
97
98     @property
99     def af(self):
100         """ Address family - AF_INET or AF_INET6 """
101         return self._af
102
103     @property
104     def bs_index(self):
105         """ BFD session index from VPP """
106         if self._bs_index is not None:
107             return self._bs_index
108         raise NotConfiguredException("not configured")
109
110     @property
111     def local_addr(self):
112         """ BFD session local address (VPP address) """
113         if self._local_addr is None:
114             if self.af == AF_INET:
115                 return self._interface.local_ip4
116             elif self.af == AF_INET6:
117                 return self._interface.local_ip6
118             else:
119                 raise Exception("Unexpected af %s' % af" % self.af)
120         return self._local_addr
121
122     @property
123     def local_addr_n(self):
124         """ BFD session local address (VPP address) - raw, suitable for API """
125         if self._local_addr is None:
126             if self.af == AF_INET:
127                 return self._interface.local_ip4n
128             elif self.af == AF_INET6:
129                 return self._interface.local_ip6n
130             else:
131                 raise Exception("Unexpected af %s' % af" % self.af)
132         return self._local_addr_n
133
134     @property
135     def peer_addr(self):
136         """ BFD session peer address """
137         return self._peer_addr
138
139     @property
140     def peer_addr_n(self):
141         """ BFD session peer address - raw, suitable for API """
142         return self._peer_addr_n
143
144     @property
145     def state(self):
146         """ BFD session state """
147         result = self.test.vapi.bfd_udp_session_dump()
148         session = None
149         for s in result:
150             if s.sw_if_index == self.interface.sw_if_index:
151                 if self.af == AF_INET \
152                         and s.is_ipv6 == 0 \
153                         and self.interface.local_ip4n == s.local_addr[:4] \
154                         and self.interface.remote_ip4n == s.peer_addr[:4]:
155                     session = s
156                     break
157         if session is None:
158             raise Exception("Could not find BFD session in VPP response: %s" %
159                             repr(result))
160         return session.state
161
162     @property
163     def desired_min_tx(self):
164         return self._desired_min_tx
165
166     @property
167     def required_min_rx(self):
168         return self._required_min_rx
169
170     @property
171     def detect_mult(self):
172         return self._detect_mult
173
174     def __init__(self, test, interface, peer_addr, local_addr=None, af=AF_INET,
175                  desired_min_tx=100000, required_min_rx=100000, detect_mult=3):
176         self._test = test
177         self._interface = interface
178         self._af = af
179         self._local_addr = local_addr
180         self._peer_addr = peer_addr
181         self._peer_addr_n = socket.inet_pton(af, peer_addr)
182         self._bs_index = None
183         self._desired_min_tx = desired_min_tx
184         self._required_min_rx = required_min_rx
185         self._detect_mult = detect_mult
186
187     def add_vpp_config(self):
188         is_ipv6 = 1 if AF_INET6 == self.af else 0
189         result = self.test.vapi.bfd_udp_add(
190             self._interface.sw_if_index,
191             self.desired_min_tx,
192             self.required_min_rx,
193             self.detect_mult,
194             self.local_addr_n,
195             self.peer_addr_n,
196             is_ipv6=is_ipv6)
197         self._bs_index = result.bs_index
198         self._test.registry.register(self, self.test.logger)
199
200     def query_vpp_config(self):
201         result = self.test.vapi.bfd_udp_session_dump()
202         session = None
203         for s in result:
204             if s.sw_if_index == self.interface.sw_if_index:
205                 if self.af == AF_INET \
206                         and s.is_ipv6 == 0 \
207                         and self.interface.local_ip4n == s.local_addr[:4] \
208                         and self.interface.remote_ip4n == s.peer_addr[:4]:
209                     session = s
210                     break
211         if session is None:
212             return False
213         return True
214
215     def remove_vpp_config(self):
216         if self._bs_index is not None:
217             is_ipv6 = 1 if AF_INET6 == self._af else 0
218             self.test.vapi.bfd_udp_del(
219                 self._interface.sw_if_index,
220                 self.local_addr_n,
221                 self.peer_addr_n,
222                 is_ipv6=is_ipv6)
223
224     def object_id(self):
225         return "bfd-udp-%d" % self.bs_index
226
227     def __str__(self):
228         return self.object_id()
229
230     def admin_up(self):
231         self.test.vapi.bfd_session_set_flags(self.bs_index, 1)