]>
Commit | Line | Data |
---|---|---|
52df8228 CF |
1 | /* |
2 | * IS-IS Rout(e)ing protocol - BFD support | |
3 | * | |
4 | * Copyright (C) 2018 Christian Franke | |
5 | * | |
6 | * This file is part of FreeRangeRouting (FRR) | |
7 | * | |
8 | * FRR is free software; you can redistribute it and/or modify it | |
9 | * under the terms of the GNU General Public License as published by the | |
10 | * Free Software Foundation; either version 2, or (at your option) any | |
11 | * later version. | |
12 | * | |
13 | * FRR is distributed in the hope that it will be useful, but | |
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
16 | * General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License along | |
19 | * with this program; see the file COPYING; if not, write to the Free Software | |
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
21 | */ | |
22 | #include <zebra.h> | |
23 | ||
24 | #include "zclient.h" | |
25 | #include "bfd.h" | |
26 | ||
27 | #include "isisd/isis_bfd.h" | |
28 | #include "isisd/isis_zebra.h" | |
215eccb0 CF |
29 | #include "isisd/isis_common.h" |
30 | #include "isisd/isis_constants.h" | |
31 | #include "isisd/isis_adjacency.h" | |
32 | #include "isisd/isis_circuit.h" | |
3015e3d1 | 33 | #include "isisd/isisd.h" |
215eccb0 | 34 | #include "isisd/fabricd.h" |
52df8228 | 35 | |
20a42f01 CF |
36 | DEFINE_MTYPE_STATIC(ISISD, BFD_SESSION, "ISIS BFD Session") |
37 | ||
38 | struct bfd_session { | |
39 | struct in_addr dst_ip; | |
40 | struct in_addr src_ip; | |
41 | }; | |
42 | ||
43 | static struct bfd_session *bfd_session_new(struct in_addr *dst_ip, | |
44 | struct in_addr *src_ip) | |
45 | { | |
46 | struct bfd_session *rv; | |
47 | ||
48 | rv = XMALLOC(MTYPE_BFD_SESSION, sizeof(*rv)); | |
49 | rv->dst_ip = *dst_ip; | |
50 | rv->src_ip = *src_ip; | |
51 | return rv; | |
52 | } | |
53 | ||
54 | static void bfd_session_free(struct bfd_session **session) | |
55 | { | |
56 | if (!*session) | |
57 | return; | |
58 | ||
59 | XFREE(MTYPE_BFD_SESSION, *session); | |
60 | *session = NULL; | |
61 | } | |
62 | ||
52df8228 CF |
63 | static int isis_bfd_interface_dest_update(int command, struct zclient *zclient, |
64 | zebra_size_t length, vrf_id_t vrf_id) | |
65 | { | |
66 | return 0; | |
67 | } | |
68 | ||
69 | static int isis_bfd_nbr_replay(int command, struct zclient *zclient, | |
70 | zebra_size_t length, vrf_id_t vrf_id) | |
71 | { | |
72 | bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER); | |
73 | return 0; | |
74 | } | |
75 | ||
76 | static void (*orig_zebra_connected)(struct zclient *); | |
77 | static void isis_bfd_zebra_connected(struct zclient *zclient) | |
78 | { | |
79 | if (orig_zebra_connected) | |
80 | orig_zebra_connected(zclient); | |
81 | ||
82 | bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER); | |
83 | } | |
84 | ||
20a42f01 CF |
85 | static void bfd_handle_adj_down(struct isis_adjacency *adj) |
86 | { | |
87 | if (!adj->bfd_session) | |
88 | return; | |
89 | ||
90 | bfd_peer_sendmsg(zclient, NULL, AF_INET, | |
91 | &adj->bfd_session->dst_ip, | |
92 | &adj->bfd_session->src_ip, | |
93 | adj->circuit->interface->name, | |
94 | 0, /* ttl */ | |
95 | 0, /* multihop */ | |
96 | ZEBRA_BFD_DEST_DEREGISTER, | |
97 | 0, /* set_flag */ | |
98 | VRF_DEFAULT); | |
99 | bfd_session_free(&adj->bfd_session); | |
100 | } | |
101 | ||
102 | static void bfd_handle_adj_up(struct isis_adjacency *adj, int command) | |
215eccb0 | 103 | { |
20a42f01 CF |
104 | struct isis_circuit *circuit = adj->circuit; |
105 | ||
106 | if (!circuit->bfd_info | |
107 | || !circuit->ip_router | |
108 | || !adj->ipv4_address_count) | |
109 | goto out; | |
110 | ||
111 | struct list *local_ips = fabricd_ip_addrs(adj->circuit); | |
112 | if (!local_ips) | |
113 | goto out; | |
114 | ||
115 | struct in_addr *dst_ip = &adj->ipv4_addresses[0]; | |
116 | struct prefix_ipv4 *local_ip = listgetdata(listhead(local_ips)); | |
117 | struct in_addr *src_ip = &local_ip->prefix; | |
118 | ||
119 | if (adj->bfd_session) { | |
120 | if (adj->bfd_session->dst_ip.s_addr != dst_ip->s_addr | |
121 | || adj->bfd_session->src_ip.s_addr != src_ip->s_addr) | |
122 | bfd_handle_adj_down(adj); | |
123 | } | |
124 | ||
125 | if (!adj->bfd_session) | |
126 | adj->bfd_session = bfd_session_new(dst_ip, src_ip); | |
127 | ||
128 | bfd_peer_sendmsg(zclient, circuit->bfd_info, AF_INET, | |
129 | &adj->bfd_session->dst_ip, | |
130 | &adj->bfd_session->src_ip, | |
131 | circuit->interface->name, | |
132 | 0, /* ttl */ | |
133 | 0, /* multihop */ | |
134 | command, | |
135 | 0, /* set flag */ | |
136 | VRF_DEFAULT); | |
215eccb0 | 137 | return; |
20a42f01 CF |
138 | out: |
139 | bfd_handle_adj_down(adj); | |
140 | } | |
141 | ||
142 | static int bfd_handle_adj_state_change(struct isis_adjacency *adj) | |
143 | { | |
144 | if (adj->adj_state == ISIS_ADJ_UP) | |
145 | bfd_handle_adj_up(adj, ZEBRA_BFD_DEST_REGISTER); | |
146 | else | |
147 | bfd_handle_adj_down(adj); | |
148 | return 0; | |
149 | } | |
150 | ||
151 | static void bfd_adj_cmd(struct isis_adjacency *adj, int command) | |
152 | { | |
153 | if (adj->adj_state == ISIS_ADJ_UP | |
154 | && command != ZEBRA_BFD_DEST_DEREGISTER) { | |
155 | bfd_handle_adj_up(adj, command); | |
156 | } else { | |
157 | bfd_handle_adj_down(adj); | |
158 | } | |
159 | } | |
160 | ||
161 | void isis_bfd_circuit_cmd(struct isis_circuit *circuit, int command) | |
162 | { | |
163 | switch (circuit->circ_type) { | |
164 | case CIRCUIT_T_BROADCAST: | |
165 | for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) { | |
166 | struct list *adjdb = circuit->u.bc.adjdb[level - 1]; | |
167 | ||
168 | struct listnode *node; | |
169 | struct isis_adjacency *adj; | |
170 | for (ALL_LIST_ELEMENTS_RO(adjdb, node, adj)) | |
171 | bfd_adj_cmd(adj, command); | |
172 | } | |
173 | break; | |
174 | case CIRCUIT_T_P2P: | |
175 | if (circuit->u.p2p.neighbor) | |
176 | bfd_adj_cmd(circuit->u.p2p.neighbor, command); | |
177 | break; | |
178 | default: | |
179 | break; | |
180 | } | |
215eccb0 CF |
181 | } |
182 | ||
183 | void isis_bfd_circuit_param_set(struct isis_circuit *circuit, | |
184 | uint32_t min_rx, uint32_t min_tx, | |
185 | uint32_t detect_mult, int defaults) | |
186 | { | |
187 | int command = 0; | |
188 | ||
189 | bfd_set_param(&circuit->bfd_info, min_rx, | |
190 | min_tx, detect_mult, defaults, &command); | |
191 | ||
192 | if (command) | |
193 | isis_bfd_circuit_cmd(circuit, command); | |
194 | } | |
195 | ||
3015e3d1 CF |
196 | static int bfd_circuit_write_settings(struct isis_circuit *circuit, |
197 | struct vty *vty) | |
198 | { | |
199 | struct bfd_info *bfd_info = circuit->bfd_info; | |
200 | ||
201 | if (!bfd_info) | |
202 | return 0; | |
203 | ||
204 | #if HAVE_BFDD == 0 | |
205 | if (CHECK_FLAG(bfd_info->flags, BFD_FLAG_PARAM_CFG)) { | |
206 | vty_out(vty, " %s bfd %" PRIu8 " %" PRIu32 " %" PRIu32 "\n", | |
207 | PROTO_NAME, bfd_info->detect_mult, | |
208 | bfd_info->required_min_rx, bfd_info->desired_min_tx); | |
209 | } else | |
210 | #endif | |
211 | vty_out(vty, " %s bfd\n", PROTO_NAME); | |
212 | return 1; | |
213 | } | |
214 | ||
52df8228 CF |
215 | void isis_bfd_init(void) |
216 | { | |
217 | bfd_gbl_init(); | |
218 | ||
219 | orig_zebra_connected = zclient->zebra_connected; | |
220 | zclient->zebra_connected = isis_bfd_zebra_connected; | |
221 | zclient->interface_bfd_dest_update = isis_bfd_interface_dest_update; | |
222 | zclient->bfd_dest_replay = isis_bfd_nbr_replay; | |
20a42f01 CF |
223 | hook_register(isis_adj_state_change_hook, |
224 | bfd_handle_adj_state_change); | |
3015e3d1 CF |
225 | hook_register(isis_circuit_config_write, |
226 | bfd_circuit_write_settings); | |
52df8228 | 227 | } |