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