blob: 57a5bd8675159649519eaeaa0b4bfe8ba08979c9 [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:
114 return self._interface.local_ip4
115 return self._local_addr
116
117 @property
118 def local_addr_n(self):
119 """ BFD session local address (VPP address) - raw, suitable for API """
120 if self._local_addr is None:
121 return self._interface.local_ip4n
122 return self._local_addr_n
123
124 @property
125 def peer_addr(self):
126 """ BFD session peer address """
127 return self._peer_addr
128
129 @property
130 def peer_addr_n(self):
131 """ BFD session peer address - raw, suitable for API """
132 return self._peer_addr_n
133
134 @property
135 def state(self):
136 """ BFD session state """
137 result = self.test.vapi.bfd_udp_session_dump()
138 session = None
139 for s in result:
140 if s.sw_if_index == self.interface.sw_if_index:
141 if self.af == AF_INET \
142 and s.is_ipv6 == 0 \
143 and self.interface.local_ip4n == s.local_addr[:4] \
144 and self.interface.remote_ip4n == s.peer_addr[:4]:
145 session = s
146 break
147 if session is None:
Klement Sekera10db26f2017-01-11 08:16:53 +0100148 raise Exception("Could not find BFD session in VPP response: %s" %
149 repr(result))
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200150 return session.state
151
152 @property
153 def desired_min_tx(self):
154 return self._desired_min_tx
155
156 @property
157 def required_min_rx(self):
158 return self._required_min_rx
159
160 @property
161 def detect_mult(self):
162 return self._detect_mult
163
Klement Sekerae4504c62016-12-08 10:16:41 +0100164 def __init__(self, test, interface, peer_addr, local_addr=None, af=AF_INET,
165 desired_min_tx=100000, required_min_rx=100000, detect_mult=3):
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200166 self._test = test
167 self._interface = interface
168 self._af = af
169 self._local_addr = local_addr
170 self._peer_addr = peer_addr
171 self._peer_addr_n = socket.inet_pton(af, peer_addr)
172 self._bs_index = None
Klement Sekerae4504c62016-12-08 10:16:41 +0100173 self._desired_min_tx = desired_min_tx
174 self._required_min_rx = required_min_rx
175 self._detect_mult = detect_mult
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200176
177 def add_vpp_config(self):
178 is_ipv6 = 1 if AF_INET6 == self.af else 0
179 result = self.test.vapi.bfd_udp_add(
180 self._interface.sw_if_index,
181 self.desired_min_tx,
182 self.required_min_rx,
183 self.detect_mult,
184 self.local_addr_n,
185 self.peer_addr_n,
186 is_ipv6=is_ipv6)
187 self._bs_index = result.bs_index
Klement Sekera10db26f2017-01-11 08:16:53 +0100188 self._test.registry.register(self, self.test.logger)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200189
190 def query_vpp_config(self):
191 result = self.test.vapi.bfd_udp_session_dump()
192 session = None
193 for s in result:
194 if s.sw_if_index == self.interface.sw_if_index:
195 if self.af == AF_INET \
196 and s.is_ipv6 == 0 \
197 and self.interface.local_ip4n == s.local_addr[:4] \
198 and self.interface.remote_ip4n == s.peer_addr[:4]:
199 session = s
200 break
201 if session is None:
202 return False
203 return True
204
205 def remove_vpp_config(self):
Klement Sekera10db26f2017-01-11 08:16:53 +0100206 if self._bs_index is not None:
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200207 is_ipv6 = 1 if AF_INET6 == self._af else 0
208 self.test.vapi.bfd_udp_del(
209 self._interface.sw_if_index,
210 self.local_addr_n,
211 self.peer_addr_n,
212 is_ipv6=is_ipv6)
213
214 def object_id(self):
215 return "bfd-udp-%d" % self.bs_index
216
Klement Sekera10db26f2017-01-11 08:16:53 +0100217 def __str__(self):
218 return self.object_id()
219
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200220 def admin_up(self):
221 self.test.vapi.bfd_session_set_flags(self.bs_index, 1)