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