]>
Commit | Line | Data |
---|---|---|
106d2fd5 | 1 | |
718e3744 | 2 | /* |
3 | * Interface functions. | |
4 | * Copyright (C) 1997, 98 Kunihiro Ishiguro | |
5 | * | |
6 | * This file is part of GNU Zebra. | |
7 | * | |
8 | * GNU Zebra is free software; you can redistribute it and/or modify | |
9 | * it under the terms of the GNU General Public License as published | |
10 | * by the Free Software Foundation; either version 2, or (at your | |
11 | * option) any later version. | |
12 | * | |
13 | * GNU Zebra 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 | |
19 | * along with GNU Zebra; see the file COPYING. If not, write to the | |
20 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
21 | * Boston, MA 02111-1307, USA. | |
22 | */ | |
23 | ||
24 | #include <zebra.h> | |
25 | ||
26 | #include "linklist.h" | |
27 | #include "vector.h" | |
28 | #include "vty.h" | |
29 | #include "command.h" | |
30 | #include "if.h" | |
31 | #include "sockunion.h" | |
32 | #include "prefix.h" | |
718e3744 | 33 | #include "memory.h" |
34 | #include "table.h" | |
35 | #include "buffer.h" | |
36 | #include "str.h" | |
37 | #include "log.h" | |
38 | \f | |
39 | /* Master list of interfaces. */ | |
40 | struct list *iflist; | |
41 | ||
42 | /* One for each program. This structure is needed to store hooks. */ | |
43 | struct if_master | |
44 | { | |
45 | int (*if_new_hook) (struct interface *); | |
46 | int (*if_delete_hook) (struct interface *); | |
47 | } if_master; | |
48 | \f | |
3a0391a9 | 49 | /* Compare interface names, returning an integer greater than, equal to, or |
50 | * less than 0, (following the strcmp convention), according to the | |
51 | * relationship between ifp1 and ifp2. Interface names consist of an | |
52 | * alphabetic prefix and a numeric suffix. The primary sort key is | |
53 | * lexicographic by name, and then numeric by number. No number sorts | |
54 | * before all numbers. Examples: de0 < de1, de100 < fxp0 < xl0, devpty < | |
55 | * devpty0, de0 < del0 | |
56 | */ | |
106d2fd5 | 57 | int |
58 | if_cmp_func (struct interface *ifp1, struct interface *ifp2) | |
59 | { | |
60 | unsigned int l1, l2; | |
61 | long int x1, x2; | |
62 | char *p1, *p2; | |
63 | int res; | |
64 | ||
65 | p1 = ifp1->name; | |
66 | p2 = ifp2->name; | |
67 | ||
90578521 | 68 | while (*p1 && *p2) { |
106d2fd5 | 69 | /* look up to any number */ |
70 | l1 = strcspn(p1, "0123456789"); | |
71 | l2 = strcspn(p2, "0123456789"); | |
72 | ||
73 | /* name lengths are different -> compare names */ | |
74 | if (l1 != l2) | |
75 | return (strcmp(p1, p2)); | |
76 | ||
3a0391a9 | 77 | /* Note that this relies on all numbers being less than all letters, so |
78 | * that de0 < del0. | |
79 | */ | |
106d2fd5 | 80 | res = strncmp(p1, p2, l1); |
81 | ||
82 | /* names are different -> compare them */ | |
83 | if (res) | |
84 | return res; | |
85 | ||
86 | /* with identical name part, go to numeric part */ | |
106d2fd5 | 87 | p1 += l1; |
88 | p2 += l1; | |
89 | ||
b06c14f2 | 90 | if (!*p1) |
91 | return -1; | |
92 | if (!*p2) | |
93 | return 1; | |
94 | ||
106d2fd5 | 95 | x1 = strtol(p1, &p1, 10); |
96 | x2 = strtol(p2, &p2, 10); | |
97 | ||
98 | /* let's compare numbers now */ | |
99 | if (x1 < x2) | |
100 | return -1; | |
101 | if (x1 > x2) | |
102 | return 1; | |
103 | ||
104 | /* numbers were equal, lets do it again.. | |
105 | (it happens with name like "eth123.456:789") */ | |
106 | } | |
90578521 | 107 | if (*p1) |
108 | return 1; | |
109 | if (*p2) | |
110 | return -1; | |
111 | return 0; | |
106d2fd5 | 112 | } |
113 | ||
718e3744 | 114 | /* Create new interface structure. */ |
718e3744 | 115 | struct interface * |
9035efaa | 116 | if_create (const char *name, int namelen) |
718e3744 | 117 | { |
118 | struct interface *ifp; | |
119 | ||
d2fc8896 | 120 | ifp = XCALLOC (MTYPE_IF, sizeof (struct interface)); |
121 | ifp->ifindex = IFINDEX_INTERNAL; | |
718e3744 | 122 | |
106d2fd5 | 123 | assert (name); |
d2fc8896 | 124 | assert (namelen <= INTERFACE_NAMSIZ); /* Need space for '\0' at end. */ |
106d2fd5 | 125 | strncpy (ifp->name, name, namelen); |
d2fc8896 | 126 | ifp->name[namelen] = '\0'; |
e90fbabd | 127 | if (if_lookup_by_name(ifp->name) == NULL) |
128 | listnode_add_sort (iflist, ifp); | |
d2fc8896 | 129 | else |
130 | zlog_err("if_create(%s): corruption detected -- interface with this " | |
131 | "name exists already!", ifp->name); | |
718e3744 | 132 | ifp->connected = list_new (); |
133 | ifp->connected->del = (void (*) (void *)) connected_free; | |
134 | ||
135 | if (if_master.if_new_hook) | |
136 | (*if_master.if_new_hook) (ifp); | |
137 | ||
138 | return ifp; | |
139 | } | |
140 | ||
d2fc8896 | 141 | /* Delete interface structure. */ |
718e3744 | 142 | void |
d2fc8896 | 143 | if_delete_retain (struct interface *ifp) |
718e3744 | 144 | { |
718e3744 | 145 | if (if_master.if_delete_hook) |
146 | (*if_master.if_delete_hook) (ifp); | |
147 | ||
148 | /* Free connected address list */ | |
149 | list_delete (ifp->connected); | |
d2fc8896 | 150 | } |
151 | ||
152 | /* Delete and free interface structure. */ | |
153 | void | |
154 | if_delete (struct interface *ifp) | |
155 | { | |
156 | listnode_delete (iflist, ifp); | |
157 | ||
158 | if_delete_retain(ifp); | |
718e3744 | 159 | |
160 | XFREE (MTYPE_IF, ifp); | |
161 | } | |
162 | ||
163 | /* Add hook to interface master. */ | |
164 | void | |
165 | if_add_hook (int type, int (*func)(struct interface *ifp)) | |
166 | { | |
167 | switch (type) { | |
168 | case IF_NEW_HOOK: | |
169 | if_master.if_new_hook = func; | |
170 | break; | |
171 | case IF_DELETE_HOOK: | |
172 | if_master.if_delete_hook = func; | |
173 | break; | |
174 | default: | |
175 | break; | |
176 | } | |
177 | } | |
178 | ||
179 | /* Interface existance check by index. */ | |
180 | struct interface * | |
181 | if_lookup_by_index (unsigned int index) | |
182 | { | |
52dc7ee6 | 183 | struct listnode *node; |
718e3744 | 184 | struct interface *ifp; |
185 | ||
1eb8ef25 | 186 | for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) |
718e3744 | 187 | { |
718e3744 | 188 | if (ifp->ifindex == index) |
189 | return ifp; | |
190 | } | |
191 | return NULL; | |
192 | } | |
193 | ||
8cc4198f | 194 | const char * |
718e3744 | 195 | ifindex2ifname (unsigned int index) |
196 | { | |
718e3744 | 197 | struct interface *ifp; |
198 | ||
d2fc8896 | 199 | return ((ifp = if_lookup_by_index(index)) != NULL) ? |
8cc4198f | 200 | ifp->name : "unknown"; |
d2fc8896 | 201 | } |
202 | ||
203 | unsigned int | |
204 | ifname2ifindex (const char *name) | |
205 | { | |
206 | struct interface *ifp; | |
207 | ||
3e4ee959 PJ |
208 | return ((ifp = if_lookup_by_name(name)) != NULL) ? ifp->ifindex |
209 | : IFINDEX_INTERNAL; | |
718e3744 | 210 | } |
211 | ||
212 | /* Interface existance check by interface name. */ | |
213 | struct interface * | |
9035efaa | 214 | if_lookup_by_name (const char *name) |
718e3744 | 215 | { |
52dc7ee6 | 216 | struct listnode *node; |
718e3744 | 217 | struct interface *ifp; |
3e4ee959 PJ |
218 | |
219 | if (name) | |
220 | for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) | |
221 | { | |
222 | if (strcmp(name, ifp->name) == 0) | |
223 | return ifp; | |
224 | } | |
718e3744 | 225 | return NULL; |
226 | } | |
227 | ||
a349198f | 228 | struct interface * |
229 | if_lookup_by_name_len(const char *name, size_t namelen) | |
230 | { | |
231 | struct listnode *node; | |
1eb8ef25 | 232 | struct interface *ifp; |
a349198f | 233 | |
234 | if (namelen > INTERFACE_NAMSIZ) | |
235 | return NULL; | |
236 | ||
1eb8ef25 | 237 | for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) |
a349198f | 238 | { |
a349198f | 239 | if (!memcmp(name, ifp->name, namelen) && (ifp->name[namelen] == '\0')) |
240 | return ifp; | |
241 | } | |
242 | return NULL; | |
243 | } | |
244 | ||
718e3744 | 245 | /* Lookup interface by IPv4 address. */ |
246 | struct interface * | |
247 | if_lookup_exact_address (struct in_addr src) | |
248 | { | |
52dc7ee6 | 249 | struct listnode *node; |
250 | struct listnode *cnode; | |
718e3744 | 251 | struct interface *ifp; |
252 | struct prefix *p; | |
253 | struct connected *c; | |
254 | ||
1eb8ef25 | 255 | for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) |
718e3744 | 256 | { |
1eb8ef25 | 257 | for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, c)) |
718e3744 | 258 | { |
718e3744 | 259 | p = c->address; |
260 | ||
261 | if (p && p->family == AF_INET) | |
262 | { | |
263 | if (IPV4_ADDR_SAME (&p->u.prefix4, &src)) | |
264 | return ifp; | |
265 | } | |
266 | } | |
267 | } | |
268 | return NULL; | |
269 | } | |
270 | ||
271 | /* Lookup interface by IPv4 address. */ | |
272 | struct interface * | |
273 | if_lookup_address (struct in_addr src) | |
274 | { | |
52dc7ee6 | 275 | struct listnode *node; |
718e3744 | 276 | struct prefix addr; |
3fb9cd6e | 277 | int bestlen = 0; |
52dc7ee6 | 278 | struct listnode *cnode; |
718e3744 | 279 | struct interface *ifp; |
718e3744 | 280 | struct connected *c; |
281 | struct interface *match; | |
282 | ||
718e3744 | 283 | addr.family = AF_INET; |
284 | addr.u.prefix4 = src; | |
285 | addr.prefixlen = IPV4_MAX_BITLEN; | |
286 | ||
287 | match = NULL; | |
288 | ||
1eb8ef25 | 289 | for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) |
718e3744 | 290 | { |
1eb8ef25 | 291 | for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, c)) |
718e3744 | 292 | { |
e4529636 AS |
293 | if (c->address && (c->address->family == AF_INET) && |
294 | prefix_match(CONNECTED_PREFIX(c), &addr) && | |
295 | (c->address->prefixlen > bestlen)) | |
718e3744 | 296 | { |
e4529636 AS |
297 | bestlen = c->address->prefixlen; |
298 | match = ifp; | |
718e3744 | 299 | } |
300 | } | |
301 | } | |
302 | return match; | |
303 | } | |
304 | ||
305 | /* Get interface by name if given name interface doesn't exist create | |
306 | one. */ | |
307 | struct interface * | |
9035efaa | 308 | if_get_by_name (const char *name) |
718e3744 | 309 | { |
310 | struct interface *ifp; | |
311 | ||
a349198f | 312 | return ((ifp = if_lookup_by_name(name)) != NULL) ? ifp : |
08dbfb69 | 313 | if_create(name, strlen(name)); |
a349198f | 314 | } |
315 | ||
316 | struct interface * | |
317 | if_get_by_name_len(const char *name, size_t namelen) | |
318 | { | |
319 | struct interface *ifp; | |
320 | ||
321 | return ((ifp = if_lookup_by_name_len(name, namelen)) != NULL) ? ifp : | |
322 | if_create(name, namelen); | |
718e3744 | 323 | } |
324 | ||
325 | /* Does interface up ? */ | |
326 | int | |
327 | if_is_up (struct interface *ifp) | |
328 | { | |
329 | return ifp->flags & IFF_UP; | |
330 | } | |
331 | ||
2e3b2e47 | 332 | /* Is interface running? */ |
333 | int | |
334 | if_is_running (struct interface *ifp) | |
335 | { | |
336 | return ifp->flags & IFF_RUNNING; | |
337 | } | |
338 | ||
339 | /* Is the interface operative, eg. either UP & RUNNING | |
340 | or UP & !ZEBRA_INTERFACE_LINK_DETECTION */ | |
341 | int | |
342 | if_is_operative (struct interface *ifp) | |
343 | { | |
344 | return ((ifp->flags & IFF_UP) && | |
345 | (ifp->flags & IFF_RUNNING || !CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION))); | |
346 | } | |
347 | ||
718e3744 | 348 | /* Is this loopback interface ? */ |
349 | int | |
350 | if_is_loopback (struct interface *ifp) | |
351 | { | |
4ba9b924 | 352 | /* XXX: Do this better, eg what if IFF_WHATEVER means X on platform M |
353 | * but Y on platform N? | |
354 | */ | |
355 | return (ifp->flags & (IFF_LOOPBACK|IFF_NOXMIT|IFF_VIRTUAL)); | |
718e3744 | 356 | } |
357 | ||
358 | /* Does this interface support broadcast ? */ | |
359 | int | |
360 | if_is_broadcast (struct interface *ifp) | |
361 | { | |
362 | return ifp->flags & IFF_BROADCAST; | |
363 | } | |
364 | ||
365 | /* Does this interface support broadcast ? */ | |
366 | int | |
367 | if_is_pointopoint (struct interface *ifp) | |
368 | { | |
369 | return ifp->flags & IFF_POINTOPOINT; | |
370 | } | |
371 | ||
372 | /* Does this interface support multicast ? */ | |
373 | int | |
374 | if_is_multicast (struct interface *ifp) | |
375 | { | |
376 | return ifp->flags & IFF_MULTICAST; | |
377 | } | |
378 | ||
379 | /* Printout flag information into log */ | |
380 | const char * | |
381 | if_flag_dump (unsigned long flag) | |
382 | { | |
383 | int separator = 0; | |
384 | static char logbuf[BUFSIZ]; | |
385 | ||
386 | #define IFF_OUT_LOG(X,STR) \ | |
4ba9b924 | 387 | if (flag & (X)) \ |
718e3744 | 388 | { \ |
389 | if (separator) \ | |
390 | strlcat (logbuf, ",", BUFSIZ); \ | |
391 | else \ | |
392 | separator = 1; \ | |
393 | strlcat (logbuf, STR, BUFSIZ); \ | |
394 | } | |
395 | ||
630c97ce | 396 | strlcpy (logbuf, "<", BUFSIZ); |
718e3744 | 397 | IFF_OUT_LOG (IFF_UP, "UP"); |
398 | IFF_OUT_LOG (IFF_BROADCAST, "BROADCAST"); | |
399 | IFF_OUT_LOG (IFF_DEBUG, "DEBUG"); | |
400 | IFF_OUT_LOG (IFF_LOOPBACK, "LOOPBACK"); | |
401 | IFF_OUT_LOG (IFF_POINTOPOINT, "POINTOPOINT"); | |
402 | IFF_OUT_LOG (IFF_NOTRAILERS, "NOTRAILERS"); | |
403 | IFF_OUT_LOG (IFF_RUNNING, "RUNNING"); | |
404 | IFF_OUT_LOG (IFF_NOARP, "NOARP"); | |
405 | IFF_OUT_LOG (IFF_PROMISC, "PROMISC"); | |
406 | IFF_OUT_LOG (IFF_ALLMULTI, "ALLMULTI"); | |
407 | IFF_OUT_LOG (IFF_OACTIVE, "OACTIVE"); | |
408 | IFF_OUT_LOG (IFF_SIMPLEX, "SIMPLEX"); | |
409 | IFF_OUT_LOG (IFF_LINK0, "LINK0"); | |
410 | IFF_OUT_LOG (IFF_LINK1, "LINK1"); | |
411 | IFF_OUT_LOG (IFF_LINK2, "LINK2"); | |
412 | IFF_OUT_LOG (IFF_MULTICAST, "MULTICAST"); | |
4ba9b924 | 413 | IFF_OUT_LOG (IFF_NOXMIT, "NOXMIT"); |
414 | IFF_OUT_LOG (IFF_NORTEXCH, "NORTEXCH"); | |
415 | IFF_OUT_LOG (IFF_VIRTUAL, "VIRTUAL"); | |
416 | IFF_OUT_LOG (IFF_IPV4, "IPv4"); | |
417 | IFF_OUT_LOG (IFF_IPV6, "IPv6"); | |
718e3744 | 418 | |
419 | strlcat (logbuf, ">", BUFSIZ); | |
420 | ||
421 | return logbuf; | |
630c97ce | 422 | #undef IFF_OUT_LOG |
718e3744 | 423 | } |
424 | ||
425 | /* For debugging */ | |
8cc4198f | 426 | static void |
cedd7f2f | 427 | if_dump (const struct interface *ifp) |
718e3744 | 428 | { |
52dc7ee6 | 429 | struct listnode *node; |
1eb8ef25 | 430 | struct connected *c; |
718e3744 | 431 | |
4a7aac1b | 432 | zlog_info ("Interface %s index %d metric %d mtu %d " |
433 | #ifdef HAVE_IPV6 | |
434 | "mtu6 %d " | |
435 | #endif /* HAVE_IPV6 */ | |
436 | "%s", | |
718e3744 | 437 | ifp->name, ifp->ifindex, ifp->metric, ifp->mtu, |
4a7aac1b | 438 | #ifdef HAVE_IPV6 |
439 | ifp->mtu6, | |
440 | #endif /* HAVE_IPV6 */ | |
718e3744 | 441 | if_flag_dump (ifp->flags)); |
442 | ||
1eb8ef25 | 443 | for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, c)) |
718e3744 | 444 | ; |
445 | } | |
446 | ||
447 | /* Interface printing for all interface. */ | |
448 | void | |
66e5cd87 | 449 | if_dump_all (void) |
718e3744 | 450 | { |
52dc7ee6 | 451 | struct listnode *node; |
1eb8ef25 | 452 | void *p; |
718e3744 | 453 | |
1eb8ef25 | 454 | for (ALL_LIST_ELEMENTS_RO (iflist, node, p)) |
455 | if_dump (p); | |
718e3744 | 456 | } |
457 | ||
458 | DEFUN (interface_desc, | |
459 | interface_desc_cmd, | |
460 | "description .LINE", | |
461 | "Interface specific description\n" | |
462 | "Characters describing this interface\n") | |
463 | { | |
718e3744 | 464 | struct interface *ifp; |
718e3744 | 465 | |
466 | if (argc == 0) | |
467 | return CMD_SUCCESS; | |
468 | ||
469 | ifp = vty->index; | |
470 | if (ifp->desc) | |
3b8b1855 | 471 | XFREE (MTYPE_TMP, ifp->desc); |
472 | ifp->desc = argv_concat(argv, argc, 0); | |
718e3744 | 473 | |
474 | return CMD_SUCCESS; | |
475 | } | |
476 | ||
477 | DEFUN (no_interface_desc, | |
478 | no_interface_desc_cmd, | |
479 | "no description", | |
480 | NO_STR | |
481 | "Interface specific description\n") | |
482 | { | |
483 | struct interface *ifp; | |
484 | ||
485 | ifp = vty->index; | |
486 | if (ifp->desc) | |
0241684e | 487 | XFREE (MTYPE_TMP, ifp->desc); |
718e3744 | 488 | ifp->desc = NULL; |
489 | ||
490 | return CMD_SUCCESS; | |
491 | } | |
98954844 PJ |
492 | \f |
493 | #ifdef SUNOS_5 | |
494 | /* Need to handle upgrade from SUNWzebra to Quagga. SUNWzebra created | |
495 | * a seperate struct interface for each logical interface, so config | |
496 | * file may be full of 'interface fooX:Y'. Solaris however does not | |
497 | * expose logical interfaces via PF_ROUTE, so trying to track logical | |
498 | * interfaces can be fruitless, for that reason Quagga only tracks | |
499 | * the primary IP interface. | |
500 | * | |
501 | * We try accomodate SUNWzebra by: | |
502 | * - looking up the interface name, to see whether it exists, if so | |
503 | * its useable | |
504 | * - for protocol daemons, this could only because zebra told us of | |
505 | * the interface | |
506 | * - for zebra, only because it learnt from kernel | |
507 | * - if not: | |
508 | * - search the name to see if it contains a sub-ipif / logical interface | |
509 | * seperator, the ':' char. If it does: | |
510 | * - text up to that char must be the primary name - get that name. | |
511 | * if not: | |
512 | * - no idea, just get the name in its entirety. | |
513 | */ | |
514 | static struct interface * | |
515 | if_sunwzebra_get (const char *name, size_t nlen) | |
516 | { | |
517 | struct interface *ifp; | |
518 | size_t seppos = 0; | |
718e3744 | 519 | |
98954844 PJ |
520 | if ( (ifp = if_lookup_by_name_len(name, nlen)) != NULL) |
521 | return ifp; | |
522 | ||
523 | /* hunt the primary interface name... */ | |
524 | while (seppos < nlen && name[seppos] != ':') | |
525 | seppos++; | |
526 | ||
527 | /* Wont catch seperator as last char, e.g. 'foo0:' but thats invalid */ | |
528 | if (seppos < nlen) | |
529 | return if_get_by_name_len (name, seppos); | |
530 | else | |
531 | return if_get_by_name_len (name, nlen); | |
532 | } | |
533 | #endif /* SUNOS_5 */ | |
534 | \f | |
718e3744 | 535 | DEFUN (interface, |
536 | interface_cmd, | |
537 | "interface IFNAME", | |
538 | "Select an interface to configure\n" | |
539 | "Interface's name\n") | |
540 | { | |
541 | struct interface *ifp; | |
d2fc8896 | 542 | size_t sl; |
543 | ||
544 | if ((sl = strlen(argv[0])) > INTERFACE_NAMSIZ) | |
545 | { | |
546 | vty_out (vty, "%% Interface name %s is invalid: length exceeds " | |
547 | "%d characters%s", | |
548 | argv[0], INTERFACE_NAMSIZ, VTY_NEWLINE); | |
549 | return CMD_WARNING; | |
550 | } | |
718e3744 | 551 | |
98954844 PJ |
552 | #ifdef SUNOS_5 |
553 | ifp = if_sunwzebra_get (argv[0], sl); | |
554 | #else | |
a349198f | 555 | ifp = if_get_by_name_len(argv[0], sl); |
98954844 | 556 | #endif /* SUNOS_5 */ |
718e3744 | 557 | |
718e3744 | 558 | vty->index = ifp; |
559 | vty->node = INTERFACE_NODE; | |
560 | ||
561 | return CMD_SUCCESS; | |
562 | } | |
563 | ||
32d2463c | 564 | DEFUN_NOSH (no_interface, |
565 | no_interface_cmd, | |
566 | "no interface IFNAME", | |
567 | NO_STR | |
568 | "Delete a pseudo interface's configuration\n" | |
569 | "Interface's name\n") | |
570 | { | |
571 | // deleting interface | |
572 | struct interface *ifp; | |
573 | ||
574 | ifp = if_lookup_by_name (argv[0]); | |
575 | ||
576 | if (ifp == NULL) | |
d2fc8896 | 577 | { |
578 | vty_out (vty, "%% Interface %s does not exist%s", argv[0], VTY_NEWLINE); | |
579 | return CMD_WARNING; | |
580 | } | |
32d2463c | 581 | |
bfc13532 | 582 | if (CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE)) |
d2fc8896 | 583 | { |
584 | vty_out (vty, "%% Only inactive interfaces can be deleted%s", | |
585 | VTY_NEWLINE); | |
586 | return CMD_WARNING; | |
587 | } | |
32d2463c | 588 | |
589 | if_delete(ifp); | |
590 | ||
591 | return CMD_SUCCESS; | |
592 | } | |
593 | ||
718e3744 | 594 | /* For debug purpose. */ |
595 | DEFUN (show_address, | |
596 | show_address_cmd, | |
597 | "show address", | |
598 | SHOW_STR | |
599 | "address\n") | |
600 | { | |
52dc7ee6 | 601 | struct listnode *node; |
602 | struct listnode *node2; | |
718e3744 | 603 | struct interface *ifp; |
604 | struct connected *ifc; | |
605 | struct prefix *p; | |
606 | ||
1eb8ef25 | 607 | for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) |
718e3744 | 608 | { |
1eb8ef25 | 609 | for (ALL_LIST_ELEMENTS_RO (ifp->connected, node2, ifc)) |
718e3744 | 610 | { |
718e3744 | 611 | p = ifc->address; |
612 | ||
613 | if (p->family == AF_INET) | |
614 | vty_out (vty, "%s/%d%s", inet_ntoa (p->u.prefix4), p->prefixlen, | |
615 | VTY_NEWLINE); | |
616 | } | |
617 | } | |
618 | return CMD_SUCCESS; | |
619 | } | |
620 | ||
621 | /* Allocate connected structure. */ | |
622 | struct connected * | |
8cc4198f | 623 | connected_new (void) |
718e3744 | 624 | { |
393deb9b | 625 | return XCALLOC (MTYPE_CONNECTED, sizeof (struct connected)); |
718e3744 | 626 | } |
627 | ||
628 | /* Free connected structure. */ | |
629 | void | |
630 | connected_free (struct connected *connected) | |
631 | { | |
632 | if (connected->address) | |
633 | prefix_free (connected->address); | |
634 | ||
635 | if (connected->destination) | |
636 | prefix_free (connected->destination); | |
637 | ||
638 | if (connected->label) | |
9c4f1c6f | 639 | XFREE (MTYPE_CONNECTED_LABEL, connected->label); |
718e3744 | 640 | |
641 | XFREE (MTYPE_CONNECTED, connected); | |
642 | } | |
643 | ||
644 | /* Print if_addr structure. */ | |
8cc4198f | 645 | static void __attribute__ ((unused)) |
718e3744 | 646 | connected_log (struct connected *connected, char *str) |
647 | { | |
648 | struct prefix *p; | |
649 | struct interface *ifp; | |
650 | char logbuf[BUFSIZ]; | |
651 | char buf[BUFSIZ]; | |
652 | ||
653 | ifp = connected->ifp; | |
654 | p = connected->address; | |
655 | ||
656 | snprintf (logbuf, BUFSIZ, "%s interface %s %s %s/%d ", | |
657 | str, ifp->name, prefix_family_str (p), | |
658 | inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ), | |
659 | p->prefixlen); | |
660 | ||
661 | p = connected->destination; | |
662 | if (p) | |
663 | { | |
664 | strncat (logbuf, inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ), | |
665 | BUFSIZ - strlen(logbuf)); | |
666 | } | |
fc95186c | 667 | zlog (NULL, LOG_INFO, "%s", logbuf); |
718e3744 | 668 | } |
669 | ||
670 | /* If two connected address has same prefix return 1. */ | |
8cc4198f | 671 | static int |
718e3744 | 672 | connected_same_prefix (struct prefix *p1, struct prefix *p2) |
673 | { | |
674 | if (p1->family == p2->family) | |
675 | { | |
676 | if (p1->family == AF_INET && | |
677 | IPV4_ADDR_SAME (&p1->u.prefix4, &p2->u.prefix4)) | |
678 | return 1; | |
679 | #ifdef HAVE_IPV6 | |
680 | if (p1->family == AF_INET6 && | |
681 | IPV6_ADDR_SAME (&p1->u.prefix6, &p2->u.prefix6)) | |
682 | return 1; | |
683 | #endif /* HAVE_IPV6 */ | |
684 | } | |
685 | return 0; | |
686 | } | |
687 | ||
688 | struct connected * | |
689 | connected_delete_by_prefix (struct interface *ifp, struct prefix *p) | |
690 | { | |
691 | struct listnode *node; | |
692 | struct listnode *next; | |
693 | struct connected *ifc; | |
694 | ||
695 | /* In case of same prefix come, replace it with new one. */ | |
696 | for (node = listhead (ifp->connected); node; node = next) | |
697 | { | |
1eb8ef25 | 698 | ifc = listgetdata (node); |
718e3744 | 699 | next = node->next; |
700 | ||
701 | if (connected_same_prefix (ifc->address, p)) | |
702 | { | |
703 | listnode_delete (ifp->connected, ifc); | |
704 | return ifc; | |
705 | } | |
706 | } | |
707 | return NULL; | |
708 | } | |
709 | ||
727d104b | 710 | /* Find the IPv4 address on our side that will be used when packets |
711 | are sent to dst. */ | |
712 | struct connected * | |
713 | connected_lookup_address (struct interface *ifp, struct in_addr dst) | |
714 | { | |
715 | struct prefix addr; | |
52dc7ee6 | 716 | struct listnode *cnode; |
727d104b | 717 | struct connected *c; |
718 | struct connected *match; | |
719 | ||
727d104b | 720 | addr.family = AF_INET; |
721 | addr.u.prefix4 = dst; | |
722 | addr.prefixlen = IPV4_MAX_BITLEN; | |
723 | ||
724 | match = NULL; | |
725 | ||
1eb8ef25 | 726 | for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, c)) |
727d104b | 727 | { |
e4529636 AS |
728 | if (c->address && (c->address->family == AF_INET) && |
729 | prefix_match(CONNECTED_PREFIX(c), &addr) && | |
730 | (!match || (c->address->prefixlen > match->address->prefixlen))) | |
731 | match = c; | |
727d104b | 732 | } |
733 | return match; | |
734 | } | |
735 | ||
4a7aac1b | 736 | struct connected * |
737 | connected_add_by_prefix (struct interface *ifp, struct prefix *p, | |
738 | struct prefix *destination) | |
739 | { | |
740 | struct connected *ifc; | |
741 | ||
742 | /* Allocate new connected address. */ | |
743 | ifc = connected_new (); | |
744 | ifc->ifp = ifp; | |
745 | ||
746 | /* Fetch interface address */ | |
747 | ifc->address = prefix_new(); | |
748 | memcpy (ifc->address, p, sizeof(struct prefix)); | |
749 | ||
750 | /* Fetch dest address */ | |
3fb9cd6e | 751 | if (destination) |
752 | { | |
753 | ifc->destination = prefix_new(); | |
754 | memcpy (ifc->destination, destination, sizeof(struct prefix)); | |
755 | } | |
4a7aac1b | 756 | |
757 | /* Add connected address to the interface. */ | |
758 | listnode_add (ifp->connected, ifc); | |
759 | return ifc; | |
760 | } | |
761 | ||
718e3744 | 762 | #ifndef HAVE_IF_NAMETOINDEX |
763 | unsigned int | |
764 | if_nametoindex (const char *name) | |
765 | { | |
718e3744 | 766 | struct interface *ifp; |
767 | ||
018546e9 | 768 | return ((ifp = if_lookup_by_name_len(name, strnlen(name, IFNAMSIZ))) != NULL) |
769 | ? ifp->ifindex : 0; | |
718e3744 | 770 | } |
771 | #endif | |
772 | ||
773 | #ifndef HAVE_IF_INDEXTONAME | |
774 | char * | |
775 | if_indextoname (unsigned int ifindex, char *name) | |
776 | { | |
718e3744 | 777 | struct interface *ifp; |
778 | ||
d2fc8896 | 779 | if (!(ifp = if_lookup_by_index(ifindex))) |
780 | return NULL; | |
781 | strncpy (name, ifp->name, IFNAMSIZ); | |
782 | return ifp->name; | |
718e3744 | 783 | } |
784 | #endif | |
785 | \f | |
8cc4198f | 786 | #if 0 /* this route_table of struct connected's is unused |
787 | * however, it would be good to use a route_table rather than | |
788 | * a list.. | |
789 | */ | |
718e3744 | 790 | /* Interface looking up by interface's address. */ |
718e3744 | 791 | /* Interface's IPv4 address reverse lookup table. */ |
792 | struct route_table *ifaddr_ipv4_table; | |
793 | /* struct route_table *ifaddr_ipv6_table; */ | |
794 | ||
8cc4198f | 795 | static void |
718e3744 | 796 | ifaddr_ipv4_add (struct in_addr *ifaddr, struct interface *ifp) |
797 | { | |
798 | struct route_node *rn; | |
799 | struct prefix_ipv4 p; | |
800 | ||
801 | p.family = AF_INET; | |
802 | p.prefixlen = IPV4_MAX_PREFIXLEN; | |
803 | p.prefix = *ifaddr; | |
804 | ||
805 | rn = route_node_get (ifaddr_ipv4_table, (struct prefix *) &p); | |
806 | if (rn) | |
807 | { | |
808 | route_unlock_node (rn); | |
809 | zlog_info ("ifaddr_ipv4_add(): address %s is already added", | |
810 | inet_ntoa (*ifaddr)); | |
811 | return; | |
812 | } | |
813 | rn->info = ifp; | |
814 | } | |
815 | ||
8cc4198f | 816 | static void |
718e3744 | 817 | ifaddr_ipv4_delete (struct in_addr *ifaddr, struct interface *ifp) |
818 | { | |
819 | struct route_node *rn; | |
820 | struct prefix_ipv4 p; | |
821 | ||
822 | p.family = AF_INET; | |
823 | p.prefixlen = IPV4_MAX_PREFIXLEN; | |
824 | p.prefix = *ifaddr; | |
825 | ||
826 | rn = route_node_lookup (ifaddr_ipv4_table, (struct prefix *) &p); | |
827 | if (! rn) | |
828 | { | |
829 | zlog_info ("ifaddr_ipv4_delete(): can't find address %s", | |
830 | inet_ntoa (*ifaddr)); | |
831 | return; | |
832 | } | |
833 | rn->info = NULL; | |
834 | route_unlock_node (rn); | |
835 | route_unlock_node (rn); | |
836 | } | |
837 | ||
838 | /* Lookup interface by interface's IP address or interface index. */ | |
8cc4198f | 839 | static struct interface * |
718e3744 | 840 | ifaddr_ipv4_lookup (struct in_addr *addr, unsigned int ifindex) |
841 | { | |
842 | struct prefix_ipv4 p; | |
843 | struct route_node *rn; | |
844 | struct interface *ifp; | |
718e3744 | 845 | |
846 | if (addr) | |
847 | { | |
848 | p.family = AF_INET; | |
849 | p.prefixlen = IPV4_MAX_PREFIXLEN; | |
850 | p.prefix = *addr; | |
851 | ||
852 | rn = route_node_lookup (ifaddr_ipv4_table, (struct prefix *) &p); | |
853 | if (! rn) | |
854 | return NULL; | |
855 | ||
856 | ifp = rn->info; | |
857 | route_unlock_node (rn); | |
858 | return ifp; | |
859 | } | |
860 | else | |
d2fc8896 | 861 | return if_lookup_by_index(ifindex); |
718e3744 | 862 | } |
8cc4198f | 863 | #endif /* ifaddr_ipv4_table */ |
718e3744 | 864 | |
865 | /* Initialize interface list. */ | |
866 | void | |
8cc4198f | 867 | if_init (void) |
718e3744 | 868 | { |
869 | iflist = list_new (); | |
8cc4198f | 870 | #if 0 |
718e3744 | 871 | ifaddr_ipv4_table = route_table_init (); |
8cc4198f | 872 | #endif /* ifaddr_ipv4_table */ |
718e3744 | 873 | |
106d2fd5 | 874 | if (iflist) { |
875 | iflist->cmp = (int (*)(void *, void *))if_cmp_func; | |
718e3744 | 876 | return; |
106d2fd5 | 877 | } |
718e3744 | 878 | |
879 | memset (&if_master, 0, sizeof if_master); | |
880 | } | |
4bd045d5 TG |
881 | |
882 | void | |
883 | if_terminate (void) | |
884 | { | |
885 | for (;;) | |
886 | { | |
887 | struct interface *ifp; | |
888 | ||
889 | ifp = listnode_head (iflist); | |
890 | if (ifp == NULL) | |
891 | break; | |
892 | ||
893 | if_delete (ifp); | |
894 | } | |
895 | ||
896 | list_delete (iflist); | |
897 | iflist = NULL; | |
898 | } |