blob: 5171681369c1bc43042a91e0a93124247862aead [file] [log] [blame]
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001from socket import AF_INET, AF_INET6
2from scapy.all import *
3from scapy.packet import *
4from scapy.fields import *
5from framework import *
6from vpp_object import *
7from util import NumericConstant
8
9
10class 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
38class 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
56class 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
82bind_layers(UDP, BFD, dport=BFD.udp_dport)
83
84
85class 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:
Klement Sekera46a87ad2017-01-02 08:22:23 +0100114 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)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200120 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:
Klement Sekera46a87ad2017-01-02 08:22:23 +0100126 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)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200132 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:
Klement Sekera10db26f2017-01-11 08:16:53 +0100158 raise Exception("Could not find BFD session in VPP response: %s" %
159 repr(result))
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200160 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
Klement Sekerae4504c62016-12-08 10:16:41 +0100174 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):
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200176 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
Klement Sekerae4504c62016-12-08 10:16:41 +0100183 self._desired_min_tx = desired_min_tx
184 self._required_min_rx = required_min_rx
185 self._detect_mult = detect_mult
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200186
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
Klement Sekera10db26f2017-01-11 08:16:53 +0100198 self._test.registry.register(self, self.test.logger)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200199
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):
Klement Sekera10db26f2017-01-11 08:16:53 +0100216 if self._bs_index is not None:
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200217 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
Klement Sekera10db26f2017-01-11 08:16:53 +0100227 def __str__(self):
228 return self.object_id()
229
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200230 def admin_up(self):
231 self.test.vapi.bfd_session_set_flags(self.bs_index, 1)