mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-05-28 10:50:18 +00:00

An interface belongs to a specific VRF. So move the interface list into the "struct vrf". * vrf.c/vrf.h: - add a new member "struct list *iflist" to the the "struct vrf"; - call if_init() in vrf_new(); - call if_terminate() in vrf_delete(); - add utilities to access the interface list and VRF ID in the specified VRF. * if.c/if.h: - the global "iflist" now only exists for the default VRF; - the global "if_master" is initialized on the definition; - in if_create(), the interface is added into the list in the specified VRF; if the VRF does not exist, create one; - add parameters to if_init()/if_terminate() so that the interface list in the VRF can be initialized/destroyed; - in if_dump_all() scan the interfaces in all the VRFs; - add a command "show address vrf N" to show addresses in a specified VRF; - add a command "show address vrf all" to show addresses in all VRFs; - new APIs ifxxx_vrf() are added to access an interface in a specified VRF. The old interface APIs (the global variable "iflist" and the API functions) are not changed to keep the backward compatibility. The new APIs are used in the daemons which support multiple VRFs (till now only zebra). Signed-off-by: Feng Lu <lu.feng@6wind.com> Reviewed-by: Alain Ritoux <alain.ritoux@6wind.com> Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com> Acked-by: Vincent JARDIN <vincent.jardin@6wind.com> Signed-off-by: David Lamparter <equinox@opensourcerouting.org> Conflicts: lib/if.c
1165 lines
27 KiB
C
1165 lines
27 KiB
C
|
|
/*
|
|
* Interface functions.
|
|
* Copyright (C) 1997, 98 Kunihiro Ishiguro
|
|
*
|
|
* This file is part of GNU Zebra.
|
|
*
|
|
* GNU Zebra is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published
|
|
* by the Free Software Foundation; either version 2, or (at your
|
|
* option) any later version.
|
|
*
|
|
* GNU Zebra is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with GNU Zebra; see the file COPYING. If not, write to the
|
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
* Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
#include <zebra.h>
|
|
|
|
#include "linklist.h"
|
|
#include "vector.h"
|
|
#include "vty.h"
|
|
#include "command.h"
|
|
#include "vrf.h"
|
|
#include "if.h"
|
|
#include "sockunion.h"
|
|
#include "prefix.h"
|
|
#include "memory.h"
|
|
#include "table.h"
|
|
#include "buffer.h"
|
|
#include "str.h"
|
|
#include "log.h"
|
|
|
|
/* List of interfaces in only the default VRF */
|
|
struct list *iflist;
|
|
int ptm_enable = 0;
|
|
|
|
/* One for each program. This structure is needed to store hooks. */
|
|
struct if_master
|
|
{
|
|
int (*if_new_hook) (struct interface *);
|
|
int (*if_delete_hook) (struct interface *);
|
|
} if_master = {0,};
|
|
|
|
/* Compare interface names, returning an integer greater than, equal to, or
|
|
* less than 0, (following the strcmp convention), according to the
|
|
* relationship between ifp1 and ifp2. Interface names consist of an
|
|
* alphabetic prefix and a numeric suffix. The primary sort key is
|
|
* lexicographic by name, and then numeric by number. No number sorts
|
|
* before all numbers. Examples: de0 < de1, de100 < fxp0 < xl0, devpty <
|
|
* devpty0, de0 < del0
|
|
*/
|
|
int
|
|
if_cmp_func (struct interface *ifp1, struct interface *ifp2)
|
|
{
|
|
unsigned int l1, l2;
|
|
long int x1, x2;
|
|
char *p1, *p2;
|
|
int res;
|
|
|
|
p1 = ifp1->name;
|
|
p2 = ifp2->name;
|
|
|
|
while (*p1 && *p2) {
|
|
/* look up to any number */
|
|
l1 = strcspn(p1, "0123456789");
|
|
l2 = strcspn(p2, "0123456789");
|
|
|
|
/* name lengths are different -> compare names */
|
|
if (l1 != l2)
|
|
return (strcmp(p1, p2));
|
|
|
|
/* Note that this relies on all numbers being less than all letters, so
|
|
* that de0 < del0.
|
|
*/
|
|
res = strncmp(p1, p2, l1);
|
|
|
|
/* names are different -> compare them */
|
|
if (res)
|
|
return res;
|
|
|
|
/* with identical name part, go to numeric part */
|
|
p1 += l1;
|
|
p2 += l1;
|
|
|
|
if (!*p1)
|
|
return -1;
|
|
if (!*p2)
|
|
return 1;
|
|
|
|
x1 = strtol(p1, &p1, 10);
|
|
x2 = strtol(p2, &p2, 10);
|
|
|
|
/* let's compare numbers now */
|
|
if (x1 < x2)
|
|
return -1;
|
|
if (x1 > x2)
|
|
return 1;
|
|
|
|
/* numbers were equal, lets do it again..
|
|
(it happens with name like "eth123.456:789") */
|
|
}
|
|
if (*p1)
|
|
return 1;
|
|
if (*p2)
|
|
return -1;
|
|
return 0;
|
|
}
|
|
|
|
/* Create new interface structure. */
|
|
struct interface *
|
|
if_create_vrf (const char *name, int namelen, vrf_id_t vrf_id)
|
|
{
|
|
struct interface *ifp;
|
|
struct list *intf_list = vrf_iflist_get (vrf_id);
|
|
|
|
ifp = XCALLOC (MTYPE_IF, sizeof (struct interface));
|
|
ifp->ifindex = IFINDEX_INTERNAL;
|
|
|
|
assert (name);
|
|
assert (namelen <= INTERFACE_NAMSIZ); /* Need space for '\0' at end. */
|
|
strncpy (ifp->name, name, namelen);
|
|
ifp->name[namelen] = '\0';
|
|
ifp->vrf_id = vrf_id;
|
|
if (if_lookup_by_name_vrf (ifp->name, vrf_id) == NULL)
|
|
listnode_add_sort (intf_list, ifp);
|
|
else
|
|
zlog_err("if_create(%s): corruption detected -- interface with this "
|
|
"name exists already in VRF %u!", ifp->name, vrf_id);
|
|
ifp->connected = list_new ();
|
|
ifp->connected->del = (void (*) (void *)) connected_free;
|
|
|
|
ifp->nbr_connected = list_new ();
|
|
ifp->nbr_connected->del = (void (*) (void *)) nbr_connected_free;
|
|
|
|
/* Enable Link-detection by default */
|
|
SET_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION);
|
|
|
|
if (if_master.if_new_hook)
|
|
(*if_master.if_new_hook) (ifp);
|
|
|
|
return ifp;
|
|
}
|
|
|
|
struct interface *
|
|
if_create (const char *name, int namelen)
|
|
{
|
|
return if_create_vrf (name, namelen, VRF_DEFAULT);
|
|
}
|
|
|
|
/* Delete interface structure. */
|
|
void
|
|
if_delete_retain (struct interface *ifp)
|
|
{
|
|
if (if_master.if_delete_hook)
|
|
(*if_master.if_delete_hook) (ifp);
|
|
|
|
/* Free connected address list */
|
|
list_delete_all_node (ifp->connected);
|
|
|
|
/* Free connected nbr address list */
|
|
list_delete_all_node (ifp->nbr_connected);
|
|
}
|
|
|
|
/* Delete and free interface structure. */
|
|
void
|
|
if_delete (struct interface *ifp)
|
|
{
|
|
listnode_delete (vrf_iflist (ifp->vrf_id), ifp);
|
|
|
|
if_delete_retain(ifp);
|
|
|
|
list_free (ifp->connected);
|
|
list_free (ifp->nbr_connected);
|
|
|
|
XFREE (MTYPE_IF, ifp);
|
|
}
|
|
|
|
/* Add hook to interface master. */
|
|
void
|
|
if_add_hook (int type, int (*func)(struct interface *ifp))
|
|
{
|
|
switch (type) {
|
|
case IF_NEW_HOOK:
|
|
if_master.if_new_hook = func;
|
|
break;
|
|
case IF_DELETE_HOOK:
|
|
if_master.if_delete_hook = func;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Interface existance check by index. */
|
|
struct interface *
|
|
if_lookup_by_index_vrf (unsigned int index, vrf_id_t vrf_id)
|
|
{
|
|
struct listnode *node;
|
|
struct interface *ifp;
|
|
|
|
for (ALL_LIST_ELEMENTS_RO (vrf_iflist (vrf_id), node, ifp))
|
|
{
|
|
if (ifp->ifindex == index)
|
|
return ifp;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
struct interface *
|
|
if_lookup_by_index (unsigned int index)
|
|
{
|
|
return if_lookup_by_index_vrf (index, VRF_DEFAULT);
|
|
}
|
|
|
|
const char *
|
|
ifindex2ifname_vrf (unsigned int index, vrf_id_t vrf_id)
|
|
{
|
|
struct interface *ifp;
|
|
|
|
return ((ifp = if_lookup_by_index_vrf (index, vrf_id)) != NULL) ?
|
|
ifp->name : "unknown";
|
|
}
|
|
|
|
const char *
|
|
ifindex2ifname (unsigned int index)
|
|
{
|
|
return ifindex2ifname_vrf (index, VRF_DEFAULT);
|
|
}
|
|
|
|
unsigned int
|
|
ifname2ifindex_vrf (const char *name, vrf_id_t vrf_id)
|
|
{
|
|
struct interface *ifp;
|
|
|
|
return ((ifp = if_lookup_by_name_vrf (name, vrf_id)) != NULL) ? ifp->ifindex
|
|
: IFINDEX_INTERNAL;
|
|
}
|
|
|
|
unsigned int
|
|
ifname2ifindex (const char *name)
|
|
{
|
|
return ifname2ifindex_vrf (name, VRF_DEFAULT);
|
|
}
|
|
|
|
/* Interface existance check by interface name. */
|
|
struct interface *
|
|
if_lookup_by_name_vrf (const char *name, vrf_id_t vrf_id)
|
|
{
|
|
struct listnode *node;
|
|
struct interface *ifp;
|
|
|
|
if (name)
|
|
for (ALL_LIST_ELEMENTS_RO (vrf_iflist (vrf_id), node, ifp))
|
|
{
|
|
if (strcmp(name, ifp->name) == 0)
|
|
return ifp;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
struct interface *
|
|
if_lookup_by_name (const char *name)
|
|
{
|
|
return if_lookup_by_name_vrf (name, VRF_DEFAULT);
|
|
}
|
|
|
|
struct interface *
|
|
if_lookup_by_name_len_vrf (const char *name, size_t namelen, vrf_id_t vrf_id)
|
|
{
|
|
struct listnode *node;
|
|
struct interface *ifp;
|
|
|
|
if (namelen > INTERFACE_NAMSIZ)
|
|
return NULL;
|
|
|
|
for (ALL_LIST_ELEMENTS_RO (vrf_iflist (vrf_id), node, ifp))
|
|
{
|
|
if (!memcmp(name, ifp->name, namelen) && (ifp->name[namelen] == '\0'))
|
|
return ifp;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
struct interface *
|
|
if_lookup_by_name_len(const char *name, size_t namelen)
|
|
{
|
|
return if_lookup_by_name_len_vrf (name, namelen, VRF_DEFAULT);
|
|
}
|
|
|
|
/* Lookup interface by IPv4 address. */
|
|
struct interface *
|
|
if_lookup_exact_address_vrf (void *src, int family, vrf_id_t vrf_id)
|
|
{
|
|
struct listnode *node;
|
|
struct listnode *cnode;
|
|
struct interface *ifp;
|
|
struct prefix *p;
|
|
struct connected *c;
|
|
|
|
for (ALL_LIST_ELEMENTS_RO (vrf_iflist (vrf_id), node, ifp))
|
|
{
|
|
for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, c))
|
|
{
|
|
p = c->address;
|
|
|
|
if (p && (p->family == family))
|
|
{
|
|
if (family == AF_INET)
|
|
{
|
|
if (IPV4_ADDR_SAME (&p->u.prefix4, (struct in_addr *)src))
|
|
return ifp;
|
|
}
|
|
else if (family == AF_INET6)
|
|
{
|
|
if (IPV6_ADDR_SAME (&p->u.prefix4, (struct in6_addr *)src))
|
|
return ifp;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
struct interface *
|
|
if_lookup_exact_address (void *src, int family)
|
|
{
|
|
return if_lookup_exact_address_vrf (src, family, VRF_DEFAULT);
|
|
}
|
|
|
|
/* Lookup interface by IPv4 address. */
|
|
struct interface *
|
|
if_lookup_address_vrf (void *matchaddr, int family, vrf_id_t vrf_id)
|
|
{
|
|
struct listnode *node;
|
|
struct prefix addr;
|
|
int bestlen = 0;
|
|
struct listnode *cnode;
|
|
struct interface *ifp;
|
|
struct connected *c;
|
|
struct interface *match;
|
|
|
|
if (family == AF_INET)
|
|
{
|
|
addr.family = AF_INET;
|
|
addr.u.prefix4 = *((struct in_addr *)matchaddr);
|
|
addr.prefixlen = IPV4_MAX_BITLEN;
|
|
}
|
|
else if (family == AF_INET6)
|
|
{
|
|
addr.family = AF_INET6;
|
|
addr.u.prefix6 = *((struct in6_addr *)matchaddr);
|
|
addr.prefixlen = IPV6_MAX_BITLEN;
|
|
}
|
|
|
|
match = NULL;
|
|
|
|
for (ALL_LIST_ELEMENTS_RO (vrf_iflist (vrf_id), node, ifp))
|
|
{
|
|
for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, c))
|
|
{
|
|
if (c->address && (c->address->family == AF_INET) &&
|
|
prefix_match(CONNECTED_PREFIX(c), &addr) &&
|
|
(c->address->prefixlen > bestlen))
|
|
{
|
|
bestlen = c->address->prefixlen;
|
|
match = ifp;
|
|
}
|
|
}
|
|
}
|
|
return match;
|
|
}
|
|
|
|
struct interface *
|
|
if_lookup_address (void *matchaddr, int family)
|
|
{
|
|
return if_lookup_address_vrf (matchaddr, family, VRF_DEFAULT);
|
|
}
|
|
|
|
/* Lookup anchor interface by IPv4 address. */
|
|
struct connected *
|
|
if_anchor_lookup_by_address (struct in_addr src)
|
|
{
|
|
struct listnode *node;
|
|
struct listnode *cnode;
|
|
struct interface *ifp;
|
|
struct prefix *p;
|
|
struct connected *c;
|
|
|
|
for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
|
|
{
|
|
for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, c))
|
|
{
|
|
if (CHECK_FLAG(c->flags, ZEBRA_IFA_UNNUMBERED) ||
|
|
!CHECK_FLAG(c->conf, ZEBRA_IFC_REAL))
|
|
continue;
|
|
|
|
p = c->address;
|
|
|
|
if (p && p->family == AF_INET)
|
|
{
|
|
if (IPV4_ADDR_SAME (&p->u.prefix4, &src))
|
|
return c;
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/* Lookup interface by prefix */
|
|
struct interface *
|
|
if_lookup_prefix_vrf (struct prefix *prefix, vrf_id_t vrf_id)
|
|
{
|
|
struct listnode *node;
|
|
struct listnode *cnode;
|
|
struct interface *ifp;
|
|
struct connected *c;
|
|
|
|
for (ALL_LIST_ELEMENTS_RO (vrf_iflist (vrf_id), node, ifp))
|
|
{
|
|
for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, c))
|
|
{
|
|
if (prefix_cmp(c->address, prefix) == 0)
|
|
{
|
|
return ifp;
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
struct interface *
|
|
if_lookup_prefix (struct prefix *prefix)
|
|
{
|
|
return if_lookup_prefix_vrf (prefix, VRF_DEFAULT);
|
|
}
|
|
|
|
/* Get interface by name if given name interface doesn't exist create
|
|
one. */
|
|
struct interface *
|
|
if_get_by_name_vrf (const char *name, vrf_id_t vrf_id)
|
|
{
|
|
struct interface *ifp;
|
|
|
|
return ((ifp = if_lookup_by_name_vrf (name, vrf_id)) != NULL) ? ifp :
|
|
if_create_vrf (name, strlen(name), vrf_id);
|
|
}
|
|
|
|
struct interface *
|
|
if_get_by_name (const char *name)
|
|
{
|
|
return if_get_by_name_vrf (name, VRF_DEFAULT);
|
|
}
|
|
|
|
struct interface *
|
|
if_get_by_name_len_vrf (const char *name, size_t namelen, vrf_id_t vrf_id)
|
|
{
|
|
struct interface *ifp;
|
|
|
|
return ((ifp = if_lookup_by_name_len_vrf (name, namelen, vrf_id)) != NULL) ? \
|
|
ifp : if_create_vrf (name, namelen, vrf_id);
|
|
}
|
|
|
|
struct interface *
|
|
if_get_by_name_len (const char *name, size_t namelen)
|
|
{
|
|
return if_get_by_name_len_vrf (name, namelen, VRF_DEFAULT);
|
|
}
|
|
|
|
/* Does interface up ? */
|
|
int
|
|
if_is_up (struct interface *ifp)
|
|
{
|
|
return ifp->flags & IFF_UP;
|
|
}
|
|
|
|
/* Is interface running? */
|
|
int
|
|
if_is_running (struct interface *ifp)
|
|
{
|
|
return ifp->flags & IFF_RUNNING;
|
|
}
|
|
|
|
/* Is the interface operative, eg. either UP & RUNNING
|
|
or UP & !ZEBRA_INTERFACE_LINK_DETECTION and
|
|
if ptm checking is enabled, then ptm check has passed */
|
|
int
|
|
if_is_operative (struct interface *ifp)
|
|
{
|
|
return ((ifp->flags & IFF_UP) &&
|
|
(((ifp->flags & IFF_RUNNING) &&
|
|
(ifp->ptm_status || !ifp->ptm_enable)) ||
|
|
!CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION)));
|
|
}
|
|
|
|
/* Is the interface operative, eg. either UP & RUNNING
|
|
or UP & !ZEBRA_INTERFACE_LINK_DETECTION, without PTM check */
|
|
int
|
|
if_is_no_ptm_operative (struct interface *ifp)
|
|
{
|
|
return ((ifp->flags & IFF_UP) &&
|
|
((ifp->flags & IFF_RUNNING) ||
|
|
!CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION)));
|
|
}
|
|
|
|
/* Is this loopback interface ? */
|
|
int
|
|
if_is_loopback (struct interface *ifp)
|
|
{
|
|
/* XXX: Do this better, eg what if IFF_WHATEVER means X on platform M
|
|
* but Y on platform N?
|
|
*/
|
|
return (ifp->flags & (IFF_LOOPBACK|IFF_NOXMIT|IFF_VIRTUAL));
|
|
}
|
|
|
|
/* Does this interface support broadcast ? */
|
|
int
|
|
if_is_broadcast (struct interface *ifp)
|
|
{
|
|
return ifp->flags & IFF_BROADCAST;
|
|
}
|
|
|
|
/* Does this interface support broadcast ? */
|
|
int
|
|
if_is_pointopoint (struct interface *ifp)
|
|
{
|
|
return ifp->flags & IFF_POINTOPOINT;
|
|
}
|
|
|
|
/* Does this interface support multicast ? */
|
|
int
|
|
if_is_multicast (struct interface *ifp)
|
|
{
|
|
return ifp->flags & IFF_MULTICAST;
|
|
}
|
|
|
|
/* Printout flag information into log */
|
|
const char *
|
|
if_flag_dump (unsigned long flag)
|
|
{
|
|
int separator = 0;
|
|
static char logbuf[BUFSIZ];
|
|
|
|
#define IFF_OUT_LOG(X,STR) \
|
|
if (flag & (X)) \
|
|
{ \
|
|
if (separator) \
|
|
strlcat (logbuf, ",", BUFSIZ); \
|
|
else \
|
|
separator = 1; \
|
|
strlcat (logbuf, STR, BUFSIZ); \
|
|
}
|
|
|
|
strlcpy (logbuf, "<", BUFSIZ);
|
|
IFF_OUT_LOG (IFF_UP, "UP");
|
|
IFF_OUT_LOG (IFF_BROADCAST, "BROADCAST");
|
|
IFF_OUT_LOG (IFF_DEBUG, "DEBUG");
|
|
IFF_OUT_LOG (IFF_LOOPBACK, "LOOPBACK");
|
|
IFF_OUT_LOG (IFF_POINTOPOINT, "POINTOPOINT");
|
|
IFF_OUT_LOG (IFF_NOTRAILERS, "NOTRAILERS");
|
|
IFF_OUT_LOG (IFF_RUNNING, "RUNNING");
|
|
IFF_OUT_LOG (IFF_NOARP, "NOARP");
|
|
IFF_OUT_LOG (IFF_PROMISC, "PROMISC");
|
|
IFF_OUT_LOG (IFF_ALLMULTI, "ALLMULTI");
|
|
IFF_OUT_LOG (IFF_OACTIVE, "OACTIVE");
|
|
IFF_OUT_LOG (IFF_SIMPLEX, "SIMPLEX");
|
|
IFF_OUT_LOG (IFF_LINK0, "LINK0");
|
|
IFF_OUT_LOG (IFF_LINK1, "LINK1");
|
|
IFF_OUT_LOG (IFF_LINK2, "LINK2");
|
|
IFF_OUT_LOG (IFF_MULTICAST, "MULTICAST");
|
|
IFF_OUT_LOG (IFF_NOXMIT, "NOXMIT");
|
|
IFF_OUT_LOG (IFF_NORTEXCH, "NORTEXCH");
|
|
IFF_OUT_LOG (IFF_VIRTUAL, "VIRTUAL");
|
|
IFF_OUT_LOG (IFF_IPV4, "IPv4");
|
|
IFF_OUT_LOG (IFF_IPV6, "IPv6");
|
|
|
|
strlcat (logbuf, ">", BUFSIZ);
|
|
|
|
return logbuf;
|
|
#undef IFF_OUT_LOG
|
|
}
|
|
|
|
/* For debugging */
|
|
static void
|
|
if_dump (const struct interface *ifp)
|
|
{
|
|
zlog_info ("Interface %s vrf %u index %d metric %d mtu %d "
|
|
#ifdef HAVE_IPV6
|
|
"mtu6 %d "
|
|
#endif /* HAVE_IPV6 */
|
|
"%s",
|
|
ifp->name, ifp->vrf_id, ifp->ifindex, ifp->metric, ifp->mtu,
|
|
#ifdef HAVE_IPV6
|
|
ifp->mtu6,
|
|
#endif /* HAVE_IPV6 */
|
|
if_flag_dump (ifp->flags));
|
|
}
|
|
|
|
/* Interface printing for all interface. */
|
|
void
|
|
if_dump_all (void)
|
|
{
|
|
struct list *intf_list;
|
|
struct listnode *node;
|
|
void *p;
|
|
vrf_iter_t iter;
|
|
|
|
for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter))
|
|
if ((intf_list = vrf_iter2iflist (iter)) != NULL)
|
|
for (ALL_LIST_ELEMENTS_RO (intf_list, node, p))
|
|
if_dump (p);
|
|
}
|
|
|
|
DEFUN (interface_desc,
|
|
interface_desc_cmd,
|
|
"description .LINE",
|
|
"Interface specific description\n"
|
|
"Characters describing this interface\n")
|
|
{
|
|
struct interface *ifp;
|
|
|
|
if (argc == 0)
|
|
return CMD_SUCCESS;
|
|
|
|
ifp = vty->index;
|
|
if (ifp->desc)
|
|
XFREE (MTYPE_TMP, ifp->desc);
|
|
ifp->desc = argv_concat(argv, argc, 0);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (no_interface_desc,
|
|
no_interface_desc_cmd,
|
|
"no description",
|
|
NO_STR
|
|
"Interface specific description\n")
|
|
{
|
|
struct interface *ifp;
|
|
|
|
ifp = vty->index;
|
|
if (ifp->desc)
|
|
XFREE (MTYPE_TMP, ifp->desc);
|
|
ifp->desc = NULL;
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
#ifdef SUNOS_5
|
|
/* Need to handle upgrade from SUNWzebra to Quagga. SUNWzebra created
|
|
* a seperate struct interface for each logical interface, so config
|
|
* file may be full of 'interface fooX:Y'. Solaris however does not
|
|
* expose logical interfaces via PF_ROUTE, so trying to track logical
|
|
* interfaces can be fruitless, for that reason Quagga only tracks
|
|
* the primary IP interface.
|
|
*
|
|
* We try accomodate SUNWzebra by:
|
|
* - looking up the interface name, to see whether it exists, if so
|
|
* its useable
|
|
* - for protocol daemons, this could only because zebra told us of
|
|
* the interface
|
|
* - for zebra, only because it learnt from kernel
|
|
* - if not:
|
|
* - search the name to see if it contains a sub-ipif / logical interface
|
|
* seperator, the ':' char. If it does:
|
|
* - text up to that char must be the primary name - get that name.
|
|
* if not:
|
|
* - no idea, just get the name in its entirety.
|
|
*/
|
|
static struct interface *
|
|
if_sunwzebra_get (const char *name, size_t nlen, vrf_id_t vrf_id)
|
|
{
|
|
struct interface *ifp;
|
|
size_t seppos = 0;
|
|
|
|
if ( (ifp = if_lookup_by_name_len_vrf (name, nlen, vrf_id)) != NULL)
|
|
return ifp;
|
|
|
|
/* hunt the primary interface name... */
|
|
while (seppos < nlen && name[seppos] != ':')
|
|
seppos++;
|
|
|
|
/* Wont catch seperator as last char, e.g. 'foo0:' but thats invalid */
|
|
if (seppos < nlen)
|
|
return if_get_by_name_len_vrf (name, seppos, vrf_id);
|
|
else
|
|
return if_get_by_name_len_vrf (name, nlen, vrf_id);
|
|
}
|
|
#endif /* SUNOS_5 */
|
|
|
|
DEFUN (interface,
|
|
interface_cmd,
|
|
"interface IFNAME",
|
|
"Select an interface to configure\n"
|
|
"Interface's name\n")
|
|
{
|
|
struct interface *ifp;
|
|
size_t sl;
|
|
vrf_id_t vrf_id = VRF_DEFAULT;
|
|
|
|
if ((sl = strlen(argv[0])) > INTERFACE_NAMSIZ)
|
|
{
|
|
vty_out (vty, "%% Interface name %s is invalid: length exceeds "
|
|
"%d characters%s",
|
|
argv[0], INTERFACE_NAMSIZ, VTY_NEWLINE);
|
|
return CMD_WARNING;
|
|
}
|
|
|
|
#ifdef SUNOS_5
|
|
ifp = if_sunwzebra_get (argv[0], sl, vrf_id);
|
|
#else
|
|
ifp = if_get_by_name_len_vrf (argv[0], sl, vrf_id);
|
|
#endif /* SUNOS_5 */
|
|
|
|
vty->index = ifp;
|
|
vty->node = INTERFACE_NODE;
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN_NOSH (no_interface,
|
|
no_interface_cmd,
|
|
"no interface IFNAME",
|
|
NO_STR
|
|
"Delete a pseudo interface's configuration\n"
|
|
"Interface's name\n")
|
|
{
|
|
// deleting interface
|
|
struct interface *ifp;
|
|
vrf_id_t vrf_id = VRF_DEFAULT;
|
|
|
|
ifp = if_lookup_by_name_vrf (argv[0], vrf_id);
|
|
|
|
if (ifp == NULL)
|
|
{
|
|
vty_out (vty, "%% Interface %s does not exist%s", argv[0], VTY_NEWLINE);
|
|
return CMD_WARNING;
|
|
}
|
|
|
|
if (CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
|
|
{
|
|
vty_out (vty, "%% Only inactive interfaces can be deleted%s",
|
|
VTY_NEWLINE);
|
|
return CMD_WARNING;
|
|
}
|
|
|
|
if_delete(ifp);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
/* For debug purpose. */
|
|
DEFUN (show_address,
|
|
show_address_cmd,
|
|
"show address",
|
|
SHOW_STR
|
|
"address\n")
|
|
{
|
|
struct listnode *node;
|
|
struct listnode *node2;
|
|
struct interface *ifp;
|
|
struct connected *ifc;
|
|
struct prefix *p;
|
|
vrf_id_t vrf_id = VRF_DEFAULT;
|
|
|
|
if (argc > 0)
|
|
VTY_GET_INTEGER ("VRF ID", vrf_id, argv[0]);
|
|
|
|
for (ALL_LIST_ELEMENTS_RO (vrf_iflist (vrf_id), node, ifp))
|
|
{
|
|
for (ALL_LIST_ELEMENTS_RO (ifp->connected, node2, ifc))
|
|
{
|
|
p = ifc->address;
|
|
|
|
if (p->family == AF_INET)
|
|
vty_out (vty, "%s/%d%s", inet_ntoa (p->u.prefix4), p->prefixlen,
|
|
VTY_NEWLINE);
|
|
}
|
|
}
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
ALIAS (show_address,
|
|
show_address_vrf_cmd,
|
|
"show address " VRF_CMD_STR,
|
|
SHOW_STR
|
|
"address\n"
|
|
VRF_CMD_HELP_STR)
|
|
|
|
DEFUN (show_address_vrf_all,
|
|
show_address_vrf_all_cmd,
|
|
"show address " VRF_ALL_CMD_STR,
|
|
SHOW_STR
|
|
"address\n"
|
|
VRF_ALL_CMD_HELP_STR)
|
|
{
|
|
struct list *intf_list;
|
|
struct listnode *node;
|
|
struct listnode *node2;
|
|
struct interface *ifp;
|
|
struct connected *ifc;
|
|
struct prefix *p;
|
|
vrf_iter_t iter;
|
|
|
|
for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter))
|
|
{
|
|
intf_list = vrf_iter2iflist (iter);
|
|
if (!intf_list || !listcount (intf_list))
|
|
continue;
|
|
|
|
vty_out (vty, "%sVRF %u%s%s", VTY_NEWLINE, vrf_iter2id (iter),
|
|
VTY_NEWLINE, VTY_NEWLINE);
|
|
|
|
for (ALL_LIST_ELEMENTS_RO (intf_list, node, ifp))
|
|
{
|
|
for (ALL_LIST_ELEMENTS_RO (ifp->connected, node2, ifc))
|
|
{
|
|
p = ifc->address;
|
|
|
|
if (p->family == AF_INET)
|
|
vty_out (vty, "%s/%d%s", inet_ntoa (p->u.prefix4), p->prefixlen,
|
|
VTY_NEWLINE);
|
|
}
|
|
}
|
|
}
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
/* Allocate connected structure. */
|
|
struct connected *
|
|
connected_new (void)
|
|
{
|
|
return XCALLOC (MTYPE_CONNECTED, sizeof (struct connected));
|
|
}
|
|
|
|
/* Allocate nbr connected structure. */
|
|
struct nbr_connected *
|
|
nbr_connected_new (void)
|
|
{
|
|
return XCALLOC (MTYPE_NBR_CONNECTED, sizeof (struct nbr_connected));
|
|
}
|
|
|
|
/* Free connected structure. */
|
|
void
|
|
connected_free (struct connected *connected)
|
|
{
|
|
if (connected->address)
|
|
prefix_free (connected->address);
|
|
|
|
if (connected->destination)
|
|
prefix_free (connected->destination);
|
|
|
|
if (connected->label)
|
|
XFREE (MTYPE_CONNECTED_LABEL, connected->label);
|
|
|
|
XFREE (MTYPE_CONNECTED, connected);
|
|
}
|
|
|
|
/* Free nbr connected structure. */
|
|
void
|
|
nbr_connected_free (struct nbr_connected *connected)
|
|
{
|
|
if (connected->address)
|
|
prefix_free (connected->address);
|
|
|
|
XFREE (MTYPE_NBR_CONNECTED, connected);
|
|
}
|
|
|
|
/* If same interface nbr address already exists... */
|
|
struct nbr_connected *
|
|
nbr_connected_check (struct interface *ifp, struct prefix *p)
|
|
{
|
|
struct nbr_connected *ifc;
|
|
struct listnode *node;
|
|
|
|
for (ALL_LIST_ELEMENTS_RO (ifp->nbr_connected, node, ifc))
|
|
if (prefix_same (ifc->address, p))
|
|
return ifc;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/* Print if_addr structure. */
|
|
static void __attribute__ ((unused))
|
|
connected_log (struct connected *connected, char *str)
|
|
{
|
|
struct prefix *p;
|
|
struct interface *ifp;
|
|
char logbuf[BUFSIZ];
|
|
char buf[BUFSIZ];
|
|
|
|
ifp = connected->ifp;
|
|
p = connected->address;
|
|
|
|
snprintf (logbuf, BUFSIZ, "%s interface %s vrf %u %s %s/%d ",
|
|
str, ifp->name, ifp->vrf_id, prefix_family_str (p),
|
|
inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
|
|
p->prefixlen);
|
|
|
|
p = connected->destination;
|
|
if (p)
|
|
{
|
|
strncat (logbuf, inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
|
|
BUFSIZ - strlen(logbuf));
|
|
}
|
|
zlog (NULL, LOG_INFO, "%s", logbuf);
|
|
}
|
|
|
|
/* Print if_addr structure. */
|
|
static void __attribute__ ((unused))
|
|
nbr_connected_log (struct nbr_connected *connected, char *str)
|
|
{
|
|
struct prefix *p;
|
|
struct interface *ifp;
|
|
char logbuf[BUFSIZ];
|
|
char buf[BUFSIZ];
|
|
|
|
ifp = connected->ifp;
|
|
p = connected->address;
|
|
|
|
snprintf (logbuf, BUFSIZ, "%s interface %s %s %s/%d ",
|
|
str, ifp->name, prefix_family_str (p),
|
|
inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
|
|
p->prefixlen);
|
|
|
|
zlog (NULL, LOG_INFO, "%s", logbuf);
|
|
}
|
|
|
|
/* If two connected address has same prefix return 1. */
|
|
static int
|
|
connected_same_prefix (struct prefix *p1, struct prefix *p2)
|
|
{
|
|
if (p1->family == p2->family)
|
|
{
|
|
if (p1->family == AF_INET &&
|
|
IPV4_ADDR_SAME (&p1->u.prefix4, &p2->u.prefix4))
|
|
return 1;
|
|
#ifdef HAVE_IPV6
|
|
if (p1->family == AF_INET6 &&
|
|
IPV6_ADDR_SAME (&p1->u.prefix6, &p2->u.prefix6))
|
|
return 1;
|
|
#endif /* HAVE_IPV6 */
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
struct connected *
|
|
connected_delete_by_prefix (struct interface *ifp, struct prefix *p)
|
|
{
|
|
struct listnode *node;
|
|
struct listnode *next;
|
|
struct connected *ifc;
|
|
|
|
/* In case of same prefix come, replace it with new one. */
|
|
for (node = listhead (ifp->connected); node; node = next)
|
|
{
|
|
ifc = listgetdata (node);
|
|
next = node->next;
|
|
|
|
if (connected_same_prefix (ifc->address, p))
|
|
{
|
|
listnode_delete (ifp->connected, ifc);
|
|
return ifc;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/* Find the IPv4 address on our side that will be used when packets
|
|
are sent to dst. */
|
|
struct connected *
|
|
connected_lookup_address (struct interface *ifp, struct in_addr dst)
|
|
{
|
|
struct prefix addr;
|
|
struct listnode *cnode;
|
|
struct connected *c;
|
|
struct connected *match;
|
|
|
|
addr.family = AF_INET;
|
|
addr.u.prefix4 = dst;
|
|
addr.prefixlen = IPV4_MAX_BITLEN;
|
|
|
|
match = NULL;
|
|
|
|
for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, c))
|
|
{
|
|
if (c->address && (c->address->family == AF_INET) &&
|
|
prefix_match(CONNECTED_PREFIX(c), &addr) &&
|
|
(!match || (c->address->prefixlen > match->address->prefixlen)))
|
|
match = c;
|
|
}
|
|
return match;
|
|
}
|
|
|
|
struct connected *
|
|
connected_add_by_prefix (struct interface *ifp, struct prefix *p,
|
|
struct prefix *destination)
|
|
{
|
|
struct connected *ifc;
|
|
|
|
/* Allocate new connected address. */
|
|
ifc = connected_new ();
|
|
ifc->ifp = ifp;
|
|
|
|
/* Fetch interface address */
|
|
ifc->address = prefix_new();
|
|
memcpy (ifc->address, p, sizeof(struct prefix));
|
|
|
|
/* Fetch dest address */
|
|
if (destination)
|
|
{
|
|
ifc->destination = prefix_new();
|
|
memcpy (ifc->destination, destination, sizeof(struct prefix));
|
|
}
|
|
|
|
/* Add connected address to the interface. */
|
|
listnode_add (ifp->connected, ifc);
|
|
return ifc;
|
|
}
|
|
|
|
#ifndef HAVE_IF_NAMETOINDEX
|
|
unsigned int
|
|
if_nametoindex (const char *name)
|
|
{
|
|
struct interface *ifp;
|
|
|
|
return ((ifp = if_lookup_by_name_len(name, strnlen(name, IFNAMSIZ))) != NULL)
|
|
? ifp->ifindex : 0;
|
|
}
|
|
#endif
|
|
|
|
#ifndef HAVE_IF_INDEXTONAME
|
|
char *
|
|
if_indextoname (unsigned int ifindex, char *name)
|
|
{
|
|
struct interface *ifp;
|
|
|
|
if (!(ifp = if_lookup_by_index(ifindex)))
|
|
return NULL;
|
|
strncpy (name, ifp->name, IFNAMSIZ);
|
|
return ifp->name;
|
|
}
|
|
#endif
|
|
|
|
#if 0 /* this route_table of struct connected's is unused
|
|
* however, it would be good to use a route_table rather than
|
|
* a list..
|
|
*/
|
|
/* Interface looking up by interface's address. */
|
|
/* Interface's IPv4 address reverse lookup table. */
|
|
struct route_table *ifaddr_ipv4_table;
|
|
/* struct route_table *ifaddr_ipv6_table; */
|
|
|
|
static void
|
|
ifaddr_ipv4_add (struct in_addr *ifaddr, struct interface *ifp)
|
|
{
|
|
struct route_node *rn;
|
|
struct prefix_ipv4 p;
|
|
|
|
p.family = AF_INET;
|
|
p.prefixlen = IPV4_MAX_PREFIXLEN;
|
|
p.prefix = *ifaddr;
|
|
|
|
rn = route_node_get (ifaddr_ipv4_table, (struct prefix *) &p);
|
|
if (rn)
|
|
{
|
|
route_unlock_node (rn);
|
|
zlog_info ("ifaddr_ipv4_add(): address %s is already added",
|
|
inet_ntoa (*ifaddr));
|
|
return;
|
|
}
|
|
rn->info = ifp;
|
|
}
|
|
|
|
static void
|
|
ifaddr_ipv4_delete (struct in_addr *ifaddr, struct interface *ifp)
|
|
{
|
|
struct route_node *rn;
|
|
struct prefix_ipv4 p;
|
|
|
|
p.family = AF_INET;
|
|
p.prefixlen = IPV4_MAX_PREFIXLEN;
|
|
p.prefix = *ifaddr;
|
|
|
|
rn = route_node_lookup (ifaddr_ipv4_table, (struct prefix *) &p);
|
|
if (! rn)
|
|
{
|
|
zlog_info ("ifaddr_ipv4_delete(): can't find address %s",
|
|
inet_ntoa (*ifaddr));
|
|
return;
|
|
}
|
|
rn->info = NULL;
|
|
route_unlock_node (rn);
|
|
route_unlock_node (rn);
|
|
}
|
|
|
|
/* Lookup interface by interface's IP address or interface index. */
|
|
static struct interface *
|
|
ifaddr_ipv4_lookup (struct in_addr *addr, unsigned int ifindex)
|
|
{
|
|
struct prefix_ipv4 p;
|
|
struct route_node *rn;
|
|
struct interface *ifp;
|
|
|
|
if (addr)
|
|
{
|
|
p.family = AF_INET;
|
|
p.prefixlen = IPV4_MAX_PREFIXLEN;
|
|
p.prefix = *addr;
|
|
|
|
rn = route_node_lookup (ifaddr_ipv4_table, (struct prefix *) &p);
|
|
if (! rn)
|
|
return NULL;
|
|
|
|
ifp = rn->info;
|
|
route_unlock_node (rn);
|
|
return ifp;
|
|
}
|
|
else
|
|
return if_lookup_by_index(ifindex);
|
|
}
|
|
#endif /* ifaddr_ipv4_table */
|
|
|
|
/* Initialize interface list. */
|
|
void
|
|
if_init (vrf_id_t vrf_id, struct list **intf_list)
|
|
{
|
|
*intf_list = list_new ();
|
|
#if 0
|
|
ifaddr_ipv4_table = route_table_init ();
|
|
#endif /* ifaddr_ipv4_table */
|
|
|
|
(*intf_list)->cmp = (int (*)(void *, void *))if_cmp_func;
|
|
|
|
if (vrf_id == VRF_DEFAULT)
|
|
iflist = *intf_list;
|
|
}
|
|
|
|
void
|
|
if_terminate (vrf_id_t vrf_id, struct list **intf_list)
|
|
{
|
|
for (;;)
|
|
{
|
|
struct interface *ifp;
|
|
|
|
ifp = listnode_head (*intf_list);
|
|
if (ifp == NULL)
|
|
break;
|
|
|
|
if_delete (ifp);
|
|
}
|
|
|
|
list_delete (*intf_list);
|
|
*intf_list = NULL;
|
|
|
|
if (vrf_id == VRF_DEFAULT)
|
|
iflist = NULL;
|
|
}
|