]> git.proxmox.com Git - mirror_frr.git/blob - zebra/zebra_ptm.c
ptm-integration.patch
[mirror_frr.git] / zebra / zebra_ptm.c
1 /* Kernel routing table updates using netlink over GNU/Linux system.
2 * Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
3 *
4 * This file is part of GNU Zebra.
5 *
6 * GNU Zebra is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
10 *
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with GNU Zebra; see the file COPYING. If not, write to the Free
18 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 * 02111-1307, USA.
20 */
21
22 #include <zebra.h>
23 #include <sys/un.h> /* for sockaddr_un */
24 #include <net/if.h>
25 #include "zebra/zserv.h"
26 #include "zebra/interface.h"
27 #include "zebra/debug.h"
28 #include "zebra/zebra_ptm.h"
29 #include "if.h"
30 #include "command.h"
31
32 #define ZEBRA_PTM_RECONNECT_TIME_INITIAL 1 /* initial reconnect is 1s */
33 #define ZEBRA_PTM_RECONNECT_TIME_MAX 300
34 extern struct zebra_t zebrad;
35 int ptm_enable;
36
37 int zebra_ptm_sock = -1;
38 struct thread *zebra_ptm_thread = NULL;
39
40 static int zebra_ptm_reconnect_time = ZEBRA_PTM_RECONNECT_TIME_INITIAL;
41
42 static void zebra_ptm_finish(void);
43 static int zebra_ptm_socket_init(void);
44 static void zebra_ptm_process_msg(char *msg);
45 int zebra_ptm_sock_read(struct thread *);
46 static void zebra_ptm_install_commands (void);
47
48 const char ZEBRA_PTM_SOCK_NAME[] = "\0/var/run/ptmd.socket";
49
50 typedef enum ptm_msg_type {
51 PTM_LLDP = 0,
52 PTM_BFD,
53 PTM_MAX
54 } ptm_msg_t;
55
56 void
57 zebra_ptm_init (void)
58 {
59 zebra_ptm_install_commands();
60 }
61
62 int
63 zebra_ptm_connect (struct thread *t)
64 {
65 zebra_ptm_socket_init();
66
67 if (zebra_ptm_sock != -1) {
68 zebra_ptm_thread = thread_add_read (zebrad.master, zebra_ptm_sock_read, NULL, zebra_ptm_sock);
69 zebra_ptm_reconnect_time = ZEBRA_PTM_RECONNECT_TIME_INITIAL;
70 } else {
71 zlog_err("%s: Socket connect to %s failed with err = %d\n", __func__,
72 ZEBRA_PTM_SOCK_NAME, errno);
73 zebra_ptm_reconnect_time *= 2;
74 if (zebra_ptm_reconnect_time > ZEBRA_PTM_RECONNECT_TIME_MAX)
75 zebra_ptm_reconnect_time = ZEBRA_PTM_RECONNECT_TIME_MAX;
76
77 zebra_ptm_thread = thread_add_timer (zebrad.master, zebra_ptm_connect, NULL,
78 zebra_ptm_reconnect_time);
79 }
80
81 return(errno);
82 }
83
84 static void
85 zebra_ptm_finish (void)
86 {
87 if (zebra_ptm_sock != -1)
88 {
89 if (zebra_ptm_thread != NULL)
90 {
91 thread_cancel(zebra_ptm_thread);
92 zebra_ptm_thread = NULL;
93 }
94 close (zebra_ptm_sock);
95 zebra_ptm_sock = -1;
96 }
97 }
98
99 DEFUN (zebra_ptm_enable,
100 zebra_ptm_enable_cmd,
101 "ptm-enable",
102 "Enable neighbor check with specified topology\n")
103 {
104 struct listnode *i;
105 struct interface *ifp;
106
107 ptm_enable = 1;
108
109 for (ALL_LIST_ELEMENTS_RO (iflist, i, ifp))
110 if (!ifp->ptm_enable)
111 {
112 ifp->ptm_enable = 1;
113 ifp->ptm_status = 1; /* to bring down ports that may fail check */
114 }
115
116 zebra_ptm_connect(NULL);
117
118 return CMD_SUCCESS;
119 }
120
121 DEFUN (no_zebra_ptm_enable,
122 no_zebra_ptm_enable_cmd,
123 "no ptm-enable",
124 NO_STR
125 "Enable neighbor check with specified topology\n")
126 {
127 struct listnode *i;
128 struct interface *ifp;
129 int send_linkup;
130
131 ptm_enable = 0;
132 for (ALL_LIST_ELEMENTS_RO (iflist, i, ifp))
133 {
134 if (ifp->ptm_enable)
135 {
136 if (!if_is_operative(ifp))
137 send_linkup = 1;
138
139 ifp->ptm_enable = 0;
140 if (if_is_operative (ifp) && send_linkup) {
141 zlog_debug ("%s: Bringing up interface %s\n", __func__,
142 ifp->name);
143 if_up (ifp);
144 }
145 }
146 }
147 zebra_ptm_finish();
148
149 return CMD_SUCCESS;
150 }
151
152 void
153 zebra_ptm_write (struct vty *vty)
154 {
155 if (ptm_enable)
156 vty_out (vty, "ptm-enable%s", VTY_NEWLINE);
157
158 return;
159 }
160
161 static int
162 zebra_ptm_socket_init (void)
163 {
164 int ret;
165 int sock;
166 struct sockaddr_un addr;
167
168 zebra_ptm_sock = -1;
169 sock = socket (PF_UNIX, SOCK_STREAM, 0);
170 if (sock < 0)
171 return -1;
172
173 /* Make server socket. */
174 memset (&addr, 0, sizeof (struct sockaddr_un));
175 addr.sun_family = AF_UNIX;
176 memcpy (&addr.sun_path, ZEBRA_PTM_SOCK_NAME,
177 sizeof(ZEBRA_PTM_SOCK_NAME));
178
179 ret = connect(sock, (struct sockaddr *) &addr,
180 sizeof (addr.sun_family)+sizeof (ZEBRA_PTM_SOCK_NAME)-1);
181 if (ret < 0)
182 {
183 zlog_err("%s: Unable to connect to socket %s, errno=%d\n",
184 __func__, ZEBRA_PTM_SOCK_NAME, errno);
185 close (sock);
186 return -1;
187 }
188 zlog_debug ("%s: connection to ptm socket %s succeeded\n",
189 __func__, ZEBRA_PTM_SOCK_NAME);
190 zebra_ptm_sock = sock;
191 return sock;
192 }
193
194 static void
195 zebra_ptm_install_commands (void)
196 {
197 install_element (CONFIG_NODE, &zebra_ptm_enable_cmd);
198 install_element (CONFIG_NODE, &no_zebra_ptm_enable_cmd);
199 }
200
201 static void
202 zebra_ptm_process_msg (char *buf)
203 {
204 char port_name[IF_NAMESIZE+1];
205 char status[8];
206 char tgt_ip[12];
207 char type[2];
208 char byte_len[4];
209 struct interface *ifp;
210 int scan_count, bytes_read;
211 char *pos;
212 const char *delim = "\n";
213 struct in_addr dest_addr;
214 struct prefix dest_prefix;
215 ptm_msg_t msg_type;
216
217 /* the messages from the ptm ctl socket are in text only */
218 /* with a fixed format:<count> <portname> <type> <pass|fail> */
219 pos = strtok(buf, delim);
220 while (pos != NULL) {
221 if (strstr(pos, "EOF") != NULL)
222 break;
223 scan_count = sscanf(pos, "%3s %16s %1s %4s %n", byte_len, port_name, type, status, &bytes_read);
224
225 if (scan_count == 4) {
226
227 zlog_debug("%s: %s received new status %s, type %s with scan count = %d\n",
228 __func__, port_name, type, status, scan_count);
229
230 ifp = if_lookup_by_name(port_name);
231 if (ifp == NULL) {
232 zlog_err("%s: %s not found in interface list\n", __func__, port_name);
233 return;
234 }
235
236 if (strchr(type, "B") == 0) {
237 msg_type = PTM_BFD;
238 pos = pos + bytes_read;
239 scan_count = sscanf(pos, "%11s", tgt_ip);
240 } else {
241 msg_type = PTM_LLDP;
242 }
243
244 if (strcmp(status, "pass") == 0) {
245 if (!ifp->ptm_status) {
246 ifp->ptm_status = 1;
247 if (ifp->ptm_enable && if_is_no_ptm_operative (ifp))
248 if_up (ifp);
249 }
250 } else if (strcmp (status, "fail") == 0) {
251 if (ifp->ptm_status) {
252 ifp->ptm_status = 0;
253 if (ifp->ptm_enable && if_is_no_ptm_operative (ifp)) {
254 if (msg_type == PTM_BFD) {
255
256 if (inet_pton(AF_INET, tgt_ip, &dest_addr) <= 0) {
257 zlog_err ("%s: Not a valid destination address: %s",
258 __func__, tgt_ip);
259 return;
260 }
261 dest_prefix.family = AF_INET;
262 dest_prefix.u.prefix4 = dest_addr;
263 dest_prefix.prefixlen = IPV4_MAX_PREFIXLEN;
264
265 /* Send BFD message with ifp and dest_prefix to protocols */
266 } else {
267 if_down (ifp);
268 }
269 }
270 }
271 }
272 }
273 pos = strtok(NULL, delim);
274 }
275 }
276
277 int
278 zebra_ptm_sock_read (struct thread *thread)
279 {
280 int sock;
281 char rcvbuf[ZEBRA_PTM_MAX_SOCKBUF];
282 int nbytes;
283
284 sock = THREAD_FD (thread);
285
286 if (sock == -1)
287 return -1;
288
289 nbytes = recv(sock, rcvbuf, sizeof(rcvbuf), 0);
290
291 if (nbytes <= 0)
292 {
293 if (nbytes < 0 && errno != EWOULDBLOCK && errno != EAGAIN)
294 zlog_warn ("routing socket error: %s", safe_strerror (errno));
295
296 zebra_ptm_sock = -1;
297 zebra_ptm_thread = thread_add_timer (zebrad.master, zebra_ptm_connect, NULL,
298 zebra_ptm_reconnect_time);
299 return (-1);
300 }
301
302 zlog_debug ("%s: Received message \n%s\n", __func__, rcvbuf);
303 zebra_ptm_thread = thread_add_read (zebrad.master, zebra_ptm_sock_read, NULL, sock);
304
305 zebra_ptm_process_msg (rcvbuf);
306
307 return(0);
308 }