1/* 2 * Interface functions. 3 * Copyright (C) 1997, 98 Kunihiro Ishiguro 4 * 5 * This file is part of GNU Zebra. 6 * 7 * GNU Zebra is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published 9 * by the Free Software Foundation; either version 2, or (at your 10 * option) any later version. 11 * 12 * GNU Zebra is distributed in the hope that it will be useful, but 13 * WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with GNU Zebra; see the file COPYING. If not, write to the 19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 20 * Boston, MA 02111-1307, USA. 21 */ 22 23#include <zebra.h> 24 25#include "linklist.h" 26#include "vector.h" 27#include "vty.h" 28#include "command.h" 29#include "if.h" 30#include "sockunion.h" 31#include "prefix.h" 32#include "zebra/connected.h" 33#include "memory.h" 34#include "table.h" 35#include "buffer.h" 36#include "str.h" 37#include "log.h" 38 39/* Master list of interfaces. */ 40struct list *iflist; 41 42/* One for each program. This structure is needed to store hooks. */ 43struct if_master 44{ 45 int (*if_new_hook) (struct interface *); 46 int (*if_delete_hook) (struct interface *); 47} if_master; 48 49/* Create new interface structure. */ 50struct interface * 51if_new () 52{ 53 struct interface *ifp; 54 55 ifp = XMALLOC (MTYPE_IF, sizeof (struct interface)); 56 memset (ifp, 0, sizeof (struct interface)); 57 return ifp; 58} 59 60struct interface * 61if_create () 62{ 63 struct interface *ifp; 64 65 ifp = if_new (); 66 67 listnode_add (iflist, ifp); 68 ifp->connected = list_new (); 69 ifp->connected->del = (void (*) (void *)) connected_free; 70 71 if (if_master.if_new_hook) 72 (*if_master.if_new_hook) (ifp); 73 74 return ifp; 75} 76 77/* Delete and free interface structure. */ 78void 79if_delete (struct interface *ifp) 80{ 81 listnode_delete (iflist, ifp); 82 83 if (if_master.if_delete_hook) 84 (*if_master.if_delete_hook) (ifp); 85 86 /* Free connected address list */ 87 list_delete (ifp->connected); 88 89 XFREE (MTYPE_IF, ifp); 90} 91 92/* Add hook to interface master. */ 93void 94if_add_hook (int type, int (*func)(struct interface *ifp)) 95{ 96 switch (type) { 97 case IF_NEW_HOOK: 98 if_master.if_new_hook = func; 99 break; 100 case IF_DELETE_HOOK: 101 if_master.if_delete_hook = func; 102 break; 103 default: 104 break; 105 } 106} 107 108/* Interface existance check by index. */ 109struct interface * 110if_lookup_by_index (unsigned int index) 111{ 112 listnode node; 113 struct interface *ifp; 114 115 for (node = listhead (iflist); node; nextnode (node)) 116 { 117 ifp = getdata (node); 118 if (ifp->ifindex == index) 119 return ifp; 120 } 121 return NULL; 122} 123 124char * 125ifindex2ifname (unsigned int index) 126{ 127 listnode node; 128 struct interface *ifp; 129 130 for (node = listhead (iflist); node; nextnode (node)) 131 { 132 ifp = getdata (node); 133 if (ifp->ifindex == index) 134 return ifp->name; 135 } 136 return "unknown"; 137} 138 139/* Interface existance check by interface name. */ 140struct interface * 141if_lookup_by_name (char *name) 142{ 143 listnode node; 144 struct interface *ifp; 145 146 for (node = listhead (iflist); node; nextnode (node)) 147 { 148 ifp = getdata (node); 149 if (strncmp (name, ifp->name, sizeof ifp->name) == 0) 150 return ifp; 151 } 152 return NULL; 153} 154 155/* Lookup interface by IPv4 address. */ 156struct interface * 157if_lookup_exact_address (struct in_addr src) 158{ 159 listnode node; 160 listnode cnode; 161 struct interface *ifp; 162 struct prefix *p; 163 struct connected *c; 164 165 for (node = listhead (iflist); node; nextnode (node)) 166 { 167 ifp = getdata (node); 168 169 for (cnode = listhead (ifp->connected); cnode; nextnode (cnode)) 170 { 171 c = getdata (cnode); 172 173 p = c->address; 174 175 if (p && p->family == AF_INET) 176 { 177 if (IPV4_ADDR_SAME (&p->u.prefix4, &src)) 178 return ifp; 179 } 180 } 181 } 182 return NULL; 183} 184 185/* Lookup interface by IPv4 address. */ 186struct interface * 187if_lookup_address (struct in_addr src) 188{ 189 listnode node; 190 struct prefix addr; 191 struct prefix best; 192 listnode cnode; 193 struct interface *ifp; 194 struct prefix *p; 195 struct connected *c; 196 struct interface *match; 197 198 /* Zero structures - get rid of rubbish from stack */ 199 memset(&addr, 0, sizeof(addr)); 200 memset(&best, 0, sizeof(best)); 201 202 addr.family = AF_INET; 203 addr.u.prefix4 = src; 204 addr.prefixlen = IPV4_MAX_BITLEN; 205 206 match = NULL; 207 208 for (node = listhead (iflist); node; nextnode (node)) 209 { 210 ifp = getdata (node); 211 212 for (cnode = listhead (ifp->connected); cnode; nextnode (cnode)) 213 { 214 c = getdata (cnode); 215 216 if (if_is_pointopoint (ifp)) 217 { 218 p = c->address; 219 220 if (p && p->family == AF_INET) 221 { 222#ifdef OLD_RIB /* PTP links are conventionally identified 223 by the address of the far end - MAG */ 224 if (IPV4_ADDR_SAME (&p->u.prefix4, &src)) 225 return ifp; 226#endif 227 p = c->destination; 228 if (p && IPV4_ADDR_SAME (&p->u.prefix4, &src)) 229 return ifp; 230 } 231 } 232 else 233 { 234 p = c->address; 235 236 if (p->family == AF_INET) 237 { 238 if (prefix_match (p, &addr) && p->prefixlen > best.prefixlen) 239 { 240 best = *p; 241 match = ifp; 242 } 243 } 244 } 245 } 246 } 247 return match; 248} 249 250/* Get interface by name if given name interface doesn't exist create 251 one. */ 252struct interface * 253if_get_by_name (char *name) 254{ 255 struct interface *ifp; 256 257 ifp = if_lookup_by_name (name); 258 if (ifp == NULL) 259 { 260 ifp = if_create (); 261 strncpy (ifp->name, name, IFNAMSIZ); 262 } 263 return ifp; 264} 265 266/* Does interface up ? */ 267int 268if_is_up (struct interface *ifp) 269{ 270 return ifp->flags & IFF_UP; 271} 272 273/* Is this loopback interface ? */ 274int 275if_is_loopback (struct interface *ifp) 276{ 277 return ifp->flags & IFF_LOOPBACK; 278} 279 280/* Does this interface support broadcast ? */ 281int 282if_is_broadcast (struct interface *ifp) 283{ 284 return ifp->flags & IFF_BROADCAST; 285} 286 287/* Does this interface support broadcast ? */ 288int 289if_is_pointopoint (struct interface *ifp) 290{ 291 return ifp->flags & IFF_POINTOPOINT; 292} 293 294/* Does this interface support multicast ? */ 295int 296if_is_multicast (struct interface *ifp) 297{ 298/* Foxconn add by fred 20060221 */ 299// Use M.conf file instead of multicast flag // 300// M.conf create from rc/service.c // 301 FILE *fp; 302 if(!(fp=fopen("/tmp/M.conf","r"))) 303 return 0; 304 else 305 fclose(fp); 306/* Foxconn end */ 307 return ifp->flags & IFF_MULTICAST; 308} 309 310#ifdef FOX_RIP_DEBUG 311/* Printout flag information into log */ 312const char * 313if_flag_dump (unsigned long flag) 314{ 315 int separator = 0; 316 static char logbuf[BUFSIZ]; 317 318#define IFF_OUT_LOG(X,STR) \ 319 if ((X) && (flag & (X))) \ 320 { \ 321 if (separator) \ 322 strlcat (logbuf, ",", BUFSIZ); \ 323 else \ 324 separator = 1; \ 325 strlcat (logbuf, STR, BUFSIZ); \ 326 } 327 328 strlcpy (logbuf, " <", BUFSIZ); 329 IFF_OUT_LOG (IFF_UP, "UP"); 330 IFF_OUT_LOG (IFF_BROADCAST, "BROADCAST"); 331 IFF_OUT_LOG (IFF_DEBUG, "DEBUG"); 332 IFF_OUT_LOG (IFF_LOOPBACK, "LOOPBACK"); 333 IFF_OUT_LOG (IFF_POINTOPOINT, "POINTOPOINT"); 334 IFF_OUT_LOG (IFF_NOTRAILERS, "NOTRAILERS"); 335 IFF_OUT_LOG (IFF_RUNNING, "RUNNING"); 336 IFF_OUT_LOG (IFF_NOARP, "NOARP"); 337 IFF_OUT_LOG (IFF_PROMISC, "PROMISC"); 338 IFF_OUT_LOG (IFF_ALLMULTI, "ALLMULTI"); 339 IFF_OUT_LOG (IFF_OACTIVE, "OACTIVE"); 340 IFF_OUT_LOG (IFF_SIMPLEX, "SIMPLEX"); 341 IFF_OUT_LOG (IFF_LINK0, "LINK0"); 342 IFF_OUT_LOG (IFF_LINK1, "LINK1"); 343 IFF_OUT_LOG (IFF_LINK2, "LINK2"); 344 IFF_OUT_LOG (IFF_MULTICAST, "MULTICAST"); 345 346 strlcat (logbuf, ">", BUFSIZ); 347 348 return logbuf; 349} 350#endif /* FOX_RIP_DEBUG */ 351 352#ifdef FOX_CMD_SUPPORT 353/* For debugging */ 354void 355if_dump (struct interface *ifp) 356{ 357 listnode node; 358#ifdef FOX_RIP_DEBUG 359 zlog_info ("Interface %s index %d metric %d mtu %d %s", 360 ifp->name, ifp->ifindex, ifp->metric, ifp->mtu, 361 if_flag_dump (ifp->flags)); 362#endif /* FOX_RIP_DEBUG */ 363 for (node = listhead (ifp->connected); node; nextnode (node)) 364 ; 365} 366 367/* Interface printing for all interface. */ 368void 369if_dump_all () 370{ 371 listnode node; 372 373 for (node = listhead (iflist); node; nextnode (node)) 374 if_dump (getdata (node)); 375} 376 377DEFUN (interface_desc, 378 interface_desc_cmd, 379 "description .LINE", 380 "Interface specific description\n" 381 "Characters describing this interface\n") 382{ 383 int i; 384 struct interface *ifp; 385 struct buffer *b; 386 387 if (argc == 0) 388 return CMD_SUCCESS; 389 390 ifp = vty->index; 391 if (ifp->desc) 392 XFREE (0, ifp->desc); 393 394 b = buffer_new (1024); 395 for (i = 0; i < argc; i++) 396 { 397 buffer_putstr (b, (u_char *)argv[i]); 398 buffer_putc (b, ' '); 399 } 400 buffer_putc (b, '\0'); 401 402 ifp->desc = buffer_getstr (b); 403 buffer_free (b); 404 405 return CMD_SUCCESS; 406} 407 408DEFUN (no_interface_desc, 409 no_interface_desc_cmd, 410 "no description", 411 NO_STR 412 "Interface specific description\n") 413{ 414 struct interface *ifp; 415 416 ifp = vty->index; 417 if (ifp->desc) 418 XFREE (0, ifp->desc); 419 ifp->desc = NULL; 420 421 return CMD_SUCCESS; 422} 423#endif /* FOX_CMD_SUPPORT */ 424 425/* See also wrapper function zebra_interface() in zebra/interface.c */ 426DEFUN (interface, 427 interface_cmd, 428 "interface IFNAME", 429 "Select an interface to configure\n" 430 "Interface's name\n") 431{ 432 struct interface *ifp; 433 434 ifp = if_lookup_by_name (argv[0]); 435 436 if (ifp == NULL) 437 { 438 ifp = if_create (); 439 strncpy (ifp->name, argv[0], INTERFACE_NAMSIZ); 440 } 441 vty->index = ifp; 442 vty->node = INTERFACE_NODE; 443 444 return CMD_SUCCESS; 445} 446 447#ifdef FOX_CMD_SUPPORT 448/* For debug purpose. */ 449DEFUN (show_address, 450 show_address_cmd, 451 "show address", 452 SHOW_STR 453 "address\n") 454{ 455 listnode node; 456 listnode node2; 457 struct interface *ifp; 458 struct connected *ifc; 459 struct prefix *p; 460 461 for (node = listhead (iflist); node; nextnode (node)) 462 { 463 ifp = getdata (node); 464 465 for (node2 = listhead (ifp->connected); node2; nextnode (node2)) 466 { 467 ifc = getdata (node2); 468 p = ifc->address; 469 470 if (p->family == AF_INET) 471 vty_out (vty, "%s/%d%s", inet_ntoa (p->u.prefix4), p->prefixlen, 472 VTY_NEWLINE); 473 } 474 } 475 return CMD_SUCCESS; 476} 477#endif /* FOX_CMD_SUPPORT */ 478 479/* Allocate connected structure. */ 480struct connected * 481connected_new () 482{ 483 struct connected *new = XMALLOC (MTYPE_CONNECTED, sizeof (struct connected)); 484 memset (new, 0, sizeof (struct connected)); 485 return new; 486} 487 488/* Free connected structure. */ 489void 490connected_free (struct connected *connected) 491{ 492 if (connected->address) 493 prefix_free (connected->address); 494 495 if (connected->destination) 496 prefix_free (connected->destination); 497 498 if (connected->label) 499 free (connected->label); 500 501 XFREE (MTYPE_CONNECTED, connected); 502} 503 504#ifdef FOX_RIP_DEBUG 505/* Print if_addr structure. */ 506void 507connected_log (struct connected *connected, char *str) 508{ 509 struct prefix *p; 510 struct interface *ifp; 511 char logbuf[BUFSIZ]; 512 char buf[BUFSIZ]; 513 514 ifp = connected->ifp; 515 p = connected->address; 516 517 snprintf (logbuf, BUFSIZ, "%s interface %s %s %s/%d ", 518 str, ifp->name, prefix_family_str (p), 519 inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ), 520 p->prefixlen); 521 522 p = connected->destination; 523 if (p) 524 { 525 strncat (logbuf, inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ), 526 BUFSIZ - strlen(logbuf)); 527 } 528 zlog (NULL, LOG_INFO, logbuf); 529} 530#endif /* FOX_RIP_DEBUG */ 531 532/* If two connected address has same prefix return 1. */ 533int 534connected_same_prefix (struct prefix *p1, struct prefix *p2) 535{ 536 if (p1->family == p2->family) 537 { 538 if (p1->family == AF_INET && 539 IPV4_ADDR_SAME (&p1->u.prefix4, &p2->u.prefix4)) 540 return 1; 541#ifdef HAVE_IPV6 542 if (p1->family == AF_INET6 && 543 IPV6_ADDR_SAME (&p1->u.prefix6, &p2->u.prefix6)) 544 return 1; 545#endif /* HAVE_IPV6 */ 546 } 547 return 0; 548} 549 550struct connected * 551connected_delete_by_prefix (struct interface *ifp, struct prefix *p) 552{ 553 struct listnode *node; 554 struct listnode *next; 555 struct connected *ifc; 556 557 /* In case of same prefix come, replace it with new one. */ 558 for (node = listhead (ifp->connected); node; node = next) 559 { 560 ifc = getdata (node); 561 next = node->next; 562 563 if (connected_same_prefix (ifc->address, p)) 564 { 565 listnode_delete (ifp->connected, ifc); 566 return ifc; 567 } 568 } 569 return NULL; 570} 571 572/* Check the connected information is PtP style or not. */ 573int 574ifc_pointopoint (struct connected *ifc) 575{ 576 struct prefix *p; 577 int ptp = 0; 578 579 /* When interface has PtP flag. */ 580 if (if_is_pointopoint (ifc->ifp)) 581 return 1; 582 583 /* RFC3021 PtP check. */ 584 p = ifc->address; 585 586 if (p->family == AF_INET) 587 ptp = (p->prefixlen >= IPV4_MAX_PREFIXLEN - 1); 588#ifdef HAVE_IPV6 589 if (p->family == AF_INET6) 590 ptp = (p->prefixlen >= IPV6_MAX_PREFIXLEN - 1); 591#endif /* HAVE_IPV6 */ 592 593 return ptp; 594} 595 596#ifndef HAVE_IF_NAMETOINDEX 597unsigned int 598if_nametoindex (const char *name) 599{ 600 listnode node; 601 struct interface *ifp; 602 603 for (node = listhead (iflist); node; nextnode (node)) 604 { 605 ifp = getdata (node); 606 if (strcmp (ifp->name, name) == 0) 607 return ifp->ifindex; 608 } 609 return 0; 610} 611#endif 612 613#ifndef HAVE_IF_INDEXTONAME 614char * 615if_indextoname (unsigned int ifindex, char *name) 616{ 617 listnode node; 618 struct interface *ifp; 619 620 for (node = listhead (iflist); node; nextnode (node)) 621 { 622 ifp = getdata (node); 623 if (ifp->ifindex == ifindex) 624 { 625 memcpy (name, ifp->name, IFNAMSIZ); 626 return ifp->name; 627 } 628 } 629 return NULL; 630} 631#endif 632 633/* Interface looking up by interface's address. */ 634 635/* Interface's IPv4 address reverse lookup table. */ 636struct route_table *ifaddr_ipv4_table; 637/* struct route_table *ifaddr_ipv6_table; */ 638 639void 640ifaddr_ipv4_add (struct in_addr *ifaddr, struct interface *ifp) 641{ 642 struct route_node *rn; 643 struct prefix_ipv4 p; 644 645 p.family = AF_INET; 646 p.prefixlen = IPV4_MAX_PREFIXLEN; 647 p.prefix = *ifaddr; 648 649 rn = route_node_get (ifaddr_ipv4_table, (struct prefix *) &p); 650 if (rn) 651 { 652 route_unlock_node (rn); 653#ifdef FOX_RIP_DEBUG 654 zlog_info ("ifaddr_ipv4_add(): address %s is already added", 655 inet_ntoa (*ifaddr)); 656#endif /* FOX_RIP_DEBUG */ 657 return; 658 } 659 rn->info = ifp; 660} 661 662void 663ifaddr_ipv4_delete (struct in_addr *ifaddr, struct interface *ifp) 664{ 665 struct route_node *rn; 666 struct prefix_ipv4 p; 667 668 p.family = AF_INET; 669 p.prefixlen = IPV4_MAX_PREFIXLEN; 670 p.prefix = *ifaddr; 671 672 rn = route_node_lookup (ifaddr_ipv4_table, (struct prefix *) &p); 673 if (! rn) 674 { 675#ifdef FOX_RIP_DEBUG 676 zlog_info ("ifaddr_ipv4_delete(): can't find address %s", 677 inet_ntoa (*ifaddr)); 678#endif /* FOX_RIP_DEBUG */ 679 return; 680 } 681 rn->info = NULL; 682 route_unlock_node (rn); 683 route_unlock_node (rn); 684} 685 686/* Lookup interface by interface's IP address or interface index. */ 687struct interface * 688ifaddr_ipv4_lookup (struct in_addr *addr, unsigned int ifindex) 689{ 690 struct prefix_ipv4 p; 691 struct route_node *rn; 692 struct interface *ifp; 693 listnode node; 694 695 if (addr) 696 { 697 p.family = AF_INET; 698 p.prefixlen = IPV4_MAX_PREFIXLEN; 699 p.prefix = *addr; 700 701 rn = route_node_lookup (ifaddr_ipv4_table, (struct prefix *) &p); 702 if (! rn) 703 return NULL; 704 705 ifp = rn->info; 706 route_unlock_node (rn); 707 return ifp; 708 } 709 else 710 { 711 for (node = listhead (iflist); node; nextnode (node)) 712 { 713 ifp = getdata (node); 714 715 if (ifp->ifindex == ifindex) 716 return ifp; 717 } 718 } 719 return NULL; 720} 721 722/* Initialize interface list. */ 723void 724if_init (int mcast_fox_onoff) 725{ 726 iflist = list_new (); 727 ifaddr_ipv4_table = route_table_init (); 728 729 if (iflist) 730 return; 731 732 memset (&if_master, 0, sizeof if_master); 733} 734