summaryrefslogtreecommitdiffstats
path: root/zebra
diff options
context:
space:
mode:
Diffstat (limited to 'zebra')
-rw-r--r--zebra/connected.c38
-rw-r--r--zebra/connected.h4
-rw-r--r--zebra/if_netlink.c5
-rw-r--r--zebra/interface.c83
-rw-r--r--zebra/interface.h13
-rw-r--r--zebra/irdp_interface.c5
-rw-r--r--zebra/irdp_packet.c2
-rw-r--r--zebra/kernel_null.c6
-rw-r--r--zebra/kernel_socket.c4
-rw-r--r--zebra/main.c12
-rw-r--r--zebra/redistribute.c10
-rw-r--r--zebra/rib.h73
-rw-r--r--zebra/rt.h4
-rw-r--r--zebra/rt_ioctl.c4
-rw-r--r--zebra/rt_netlink.c400
-rw-r--r--zebra/rt_socket.c4
-rw-r--r--zebra/rtadv.c82
-rw-r--r--zebra/rtadv.h2
-rw-r--r--zebra/rtread_getmsg.c2
-rw-r--r--zebra/rtread_netlink.c6
-rw-r--r--zebra/rtread_proc.c3
-rw-r--r--zebra/zebra_rib.c497
-rw-r--r--zebra/zebra_vty.c128
-rw-r--r--zebra/zserv.c6
-rw-r--r--zebra/zserv.h2
25 files changed, 895 insertions, 500 deletions
diff --git a/zebra/connected.c b/zebra/connected.c
index ad3e9607..80cb8cbc 100644
--- a/zebra/connected.c
+++ b/zebra/connected.c
@@ -36,23 +36,31 @@
#include "zebra/interface.h"
#include "zebra/connected.h"
extern struct zebra_t zebrad;
+
/* withdraw a connected address */
static void
connected_withdraw (struct connected *ifc)
{
+
if (! ifc)
return;
/* Update interface address information to protocol daemon. */
if (CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
{
+ int count;
+
zebra_interface_address_delete_update (ifc->ifp, ifc);
- if_subnet_delete (ifc->ifp, ifc);
+ count = if_subnet_delete (ifc->ifp, ifc);
if (ifc->address->family == AF_INET)
+ {
connected_down_ipv4 (ifc->ifp, ifc);
+ if (count == 0)
+ rib_flush_interface (AFI_IP, ifc->ifp);
+ }
#ifdef HAVE_IPV6
else
connected_down_ipv6 (ifc->ifp, ifc);
@@ -86,7 +94,7 @@ connected_announce (struct interface *ifp, struct connected *ifc)
zebra_interface_address_add_update (ifp, ifc);
- if (if_is_up(ifp))
+ if (if_is_operative(ifp))
{
if (ifc->address->family == AF_INET)
connected_up_ipv4 (ifp, ifc);
@@ -174,6 +182,7 @@ void
connected_up_ipv4 (struct interface *ifp, struct connected *ifc)
{
struct prefix_ipv4 p;
+ struct in_addr src = ((struct prefix_ipv4 *) ifc->address)->prefix;
if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
return;
@@ -188,14 +197,15 @@ connected_up_ipv4 (struct interface *ifp, struct connected *ifc)
if (prefix_ipv4_any (&p))
return;
- rib_add_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, NULL, ifp->ifindex,
- RT_TABLE_MAIN, ifp->metric, 0);
+ rib_add_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, &src,
+ ifp->ifindex, RT_TABLE_MAIN, ifp->metric, 0,
+ RT_SCOPE_LINK, RTPROT_KERNEL);
rib_update ();
}
/* Add connected IPv4 route to the interface. */
-void
+struct connected *
connected_add_ipv4 (struct interface *ifp, int flags, struct in_addr *addr,
u_char prefixlen, struct in_addr *broad,
const char *label)
@@ -270,10 +280,10 @@ connected_add_ipv4 (struct interface *ifp, int flags, struct in_addr *addr,
ifc->label = XSTRDUP (MTYPE_CONNECTED_LABEL, label);
/* nothing to do? */
- if ((ifc = connected_implicit_withdraw (ifp, ifc)) == NULL)
- return;
-
+ ifc = connected_implicit_withdraw (ifp, ifc);
connected_announce (ifp, ifc);
+
+ return ifc;
}
void
@@ -318,6 +328,8 @@ connected_delete_ipv4 (struct interface *ifp, int flags, struct in_addr *addr,
return;
connected_withdraw (ifc);
+
+ rib_update();
}
#ifdef HAVE_IPV6
@@ -347,7 +359,7 @@ connected_up_ipv6 (struct interface *ifp, struct connected *ifc)
}
/* Add connected IPv6 route to the interface. */
-void
+struct connected *
connected_add_ipv6 (struct interface *ifp, int flags, struct in6_addr *addr,
u_char prefixlen, struct in6_addr *broad,
const char *label)
@@ -394,10 +406,10 @@ connected_add_ipv6 (struct interface *ifp, int flags, struct in6_addr *addr,
if (label)
ifc->label = XSTRDUP (MTYPE_CONNECTED_LABEL, label);
- if ((ifc = connected_implicit_withdraw (ifp, ifc)) == NULL)
- return;
-
+ ifc = connected_implicit_withdraw (ifp, ifc);
connected_announce (ifp, ifc);
+
+ return ifc;
}
void
@@ -437,5 +449,7 @@ connected_delete_ipv6 (struct interface *ifp, struct in6_addr *address,
return;
connected_withdraw (ifc);
+
+ rib_update();
}
#endif /* HAVE_IPV6 */
diff --git a/zebra/connected.h b/zebra/connected.h
index 9595ddb1..8bfe4118 100644
--- a/zebra/connected.h
+++ b/zebra/connected.h
@@ -26,7 +26,7 @@
extern struct connected *
connected_check (struct interface *ifp, struct prefix *p);
-extern void
+extern struct connected *
connected_add_ipv4 (struct interface *ifp, int flags, struct in_addr *addr,
u_char prefixlen, struct in_addr *broad,
const char *label);
@@ -39,7 +39,7 @@ extern void connected_up_ipv4 (struct interface *, struct connected *);
extern void connected_down_ipv4 (struct interface *, struct connected *);
#ifdef HAVE_IPV6
-extern void
+extern struct connected *
connected_add_ipv6 (struct interface *ifp, int flags, struct in6_addr *address,
u_char prefixlen, struct in6_addr *broad,
const char *label);
diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c
index c9c14760..701c81b6 100644
--- a/zebra/if_netlink.c
+++ b/zebra/if_netlink.c
@@ -22,12 +22,11 @@
#include <zebra.h>
-/* Extern from rt_netlink.c */
-void interface_lookup_netlink ();
+extern int interface_lookup_netlink (void);
/* Interface information read by netlink. */
void
-interface_list ()
+interface_list (void)
{
interface_lookup_netlink ();
}
diff --git a/zebra/interface.c b/zebra/interface.c
index 184b42a0..c096d611 100644
--- a/zebra/interface.c
+++ b/zebra/interface.c
@@ -41,6 +41,11 @@
#include "zebra/debug.h"
#include "zebra/irdp.h"
+#ifdef RTADV
+/* Order is intentional. Matches RFC4191. This array is also used for
+ command matching, so only modify with care. */
+const char *rtadv_pref_strs[] = { "medium", "high", "INVALID", "low", 0 };
+#endif /* RTADV */
/* Called when new interface is added. */
static int
@@ -48,8 +53,7 @@ if_zebra_new_hook (struct interface *ifp)
{
struct zebra_if *zebra_if;
- zebra_if = XMALLOC (MTYPE_TMP, sizeof (struct zebra_if));
- memset (zebra_if, 0, sizeof (struct zebra_if));
+ zebra_if = XCALLOC (MTYPE_TMP, sizeof (struct zebra_if));
zebra_if->multicast = IF_ZEBRA_MULTICAST_UNSPEC;
zebra_if->shutdown = IF_ZEBRA_SHUTDOWN_UNSPEC;
@@ -76,6 +80,7 @@ if_zebra_new_hook (struct interface *ifp)
rtadv->HomeAgentPreference = 0;
rtadv->HomeAgentLifetime = RTADV_ADV_DEFAULT_LIFETIME;
rtadv->AdvIntervalOption = 0;
+ rtadv->DefaultPreference = RTADV_PREF_MEDIUM;
rtadv->AdvPrefixList = list_new ();
}
@@ -103,6 +108,7 @@ if_zebra_delete_hook (struct interface *ifp)
route_table_finish (zebra_if->ipv4_subnets);
XFREE (MTYPE_TMP, zebra_if);
+ ifp->info = NULL;
}
return 0;
@@ -484,6 +490,54 @@ if_delete_update (struct interface *ifp)
ifp->ifindex = IFINDEX_INTERNAL;
}
+/* Interfaces can only be renamed when DOWN */
+void
+if_rename (struct interface *ifp, const char *name)
+{
+ struct interface *oifp;
+
+ UNSET_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE);
+ zebra_interface_delete_update (ifp);
+ listnode_delete (iflist, ifp);
+
+ /* rename overlaps earlier interface */
+ oifp = if_lookup_by_name(name);
+ if (oifp)
+ {
+ ifp->status |= oifp->status; /* inherit config bits */
+ if (oifp->ifindex != IFINDEX_INTERNAL)
+ {
+ zlog_err ("interface %s rename to %s overlaps with index %d",
+ ifp->name, name, oifp->ifindex);
+ if_delete_update (oifp);
+ }
+ else if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug ("interface %s index %d superseded by rename of %s",
+ oifp->name, oifp->ifindex, ifp->name);
+
+ listnode_delete (iflist, oifp);
+ XFREE (MTYPE_IF, oifp);
+ }
+
+ strncpy(ifp->name, name, INTERFACE_NAMSIZ);
+ ifp->name[INTERFACE_NAMSIZ] = 0;
+ listnode_add_sort (iflist, ifp);
+
+ zebra_interface_add_update (ifp);
+
+ SET_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE);
+
+ if (ifp->connected)
+ {
+ struct connected *ifc;
+ struct listnode *node;
+ for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, ifc))
+ zebra_interface_address_add_update (ifp, ifc);
+ }
+
+ rib_update();
+}
+
/* Interface is up. */
void
if_up (struct interface *ifp)
@@ -538,15 +592,25 @@ if_down (struct interface *ifp)
if (p->family == AF_INET)
connected_down_ipv4 (ifp, ifc);
+ }
+ }
+
+ /* Examine all static routes which direct to the interface. */
+ rib_update ();
+
#ifdef HAVE_IPV6
- else if (p->family == AF_INET6)
+ if (ifp->connected)
+ {
+ for (ALL_LIST_ELEMENTS (ifp->connected, node, next, ifc))
+ {
+ p = ifc->address;
+ if (p->family == AF_INET6)
connected_down_ipv6 (ifp, ifc);
-#endif /* HAVE_IPV6 */
}
}
- /* Examine all static routes which direct to the interface. */
rib_update ();
+#endif /* HAVE_IPV6 */
}
void
@@ -623,6 +687,9 @@ nd_dump_vty (struct vty *vty, struct interface *ifp)
VTY_NEWLINE);
vty_out (vty, " ND router advertisements live for %d seconds%s",
rtadv->AdvDefaultLifetime, VTY_NEWLINE);
+ vty_out (vty, " ND router advertisement default router preference is "
+ "%s%s", rtadv_pref_strs[rtadv->DefaultPreference],
+ VTY_NEWLINE);
if (rtadv->AdvManagedFlag)
vty_out (vty, " Hosts use DHCP to obtain routable addresses.%s",
VTY_NEWLINE);
@@ -822,6 +889,7 @@ if_dump_vty (struct vty *vty, struct interface *ifp)
#endif /* HAVE_NET_RT_IFLIST */
}
+#if 0
/* Check supported address family. */
static int
if_supported_family (int family)
@@ -834,6 +902,7 @@ if_supported_family (int family)
#endif /* HAVE_IPV6 */
return 0;
}
+#endif
/* Wrapper hook point for zebra daemon so that ifindex can be set
* DEFUN macro not used as extract.pl HAS to ignore this
@@ -1514,7 +1583,6 @@ if_config_write (struct vty *vty)
{
struct listnode *node;
struct interface *ifp;
- char buf[BUFSIZ];
for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
{
@@ -1544,10 +1612,11 @@ if_config_write (struct vty *vty)
{
if (CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED))
{
+ char buf[INET6_ADDRSTRLEN];
p = ifc->address;
vty_out (vty, " ip%s address %s/%d",
p->family == AF_INET ? "" : "v6",
- inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
+ inet_ntop (p->family, &p->u.prefix, buf, sizeof(buf)),
p->prefixlen);
if (ifc->label)
diff --git a/zebra/interface.h b/zebra/interface.h
index 0a6b0365..827729a3 100644
--- a/zebra/interface.h
+++ b/zebra/interface.h
@@ -46,7 +46,7 @@
#endif
#ifdef RTADV
-/* Router advertisement parameter. From RFC2461 and RFC3775. */
+/* Router advertisement parameter. From RFC2461, RFC3775 and RFC4191. */
struct rtadvconf
{
/* A flag indicating whether or not the router sends periodic Router
@@ -171,6 +171,13 @@ struct rtadvconf
Default: FALSE */
int AdvIntervalOption;
+
+ /* The value to be placed in the Default Router Preference field of
+ a router advertisement. See [RFC 4191 2.1 & 2.2]
+
+ Default: 0 (medium) */
+ int DefaultPreference;
+#define RTADV_PREF_MEDIUM 0x0 /* Per RFC4191. */
};
#endif /* RTADV */
@@ -187,9 +194,6 @@ struct zebra_if
/* Router advertise configuration. */
u_char rtadv_enable;
- /* Interface's address. */
- struct list *address;
-
/* Installed addresses chains tree. */
struct route_table *ipv4_subnets;
@@ -215,6 +219,7 @@ extern void if_delete_update (struct interface *ifp);
extern void if_add_update (struct interface *ifp);
extern void if_up (struct interface *);
extern void if_down (struct interface *);
+extern void if_rename (struct interface *, const char *);
extern void if_refresh (struct interface *);
extern void if_flags_update (struct interface *, uint64_t);
extern int if_subnet_add (struct interface *, struct connected *);
diff --git a/zebra/irdp_interface.c b/zebra/irdp_interface.c
index dd773402..b3a838b3 100644
--- a/zebra/irdp_interface.c
+++ b/zebra/irdp_interface.c
@@ -175,10 +175,7 @@ if_set_defaults(struct interface *ifp)
struct Adv *Adv_new (void)
{
- struct Adv *new;
- new = XMALLOC (MTYPE_TMP, sizeof (struct Adv));
- memset (new, 0, sizeof (struct Adv));
- return new;
+ return XCALLOC (MTYPE_TMP, sizeof (struct Adv));
}
static void
diff --git a/zebra/irdp_packet.c b/zebra/irdp_packet.c
index 3c5f1559..ae121ea1 100644
--- a/zebra/irdp_packet.c
+++ b/zebra/irdp_packet.c
@@ -231,7 +231,7 @@ int irdp_read_raw(struct thread *r)
struct zebra_if *zi;
struct irdp_interface *irdp;
char buf[IRDP_RX_BUF];
- int ret, ifindex;
+ int ret, ifindex = 0;
int irdp_sock = THREAD_FD (r);
t_irdp_raw = thread_add_read (zebrad.master, irdp_read_raw, NULL, irdp_sock);
diff --git a/zebra/kernel_null.c b/zebra/kernel_null.c
index 94b7b3c7..c72bbd09 100644
--- a/zebra/kernel_null.c
+++ b/zebra/kernel_null.c
@@ -12,9 +12,9 @@ int kernel_add_ipv4 (struct prefix *a, struct rib *b) { return 0; }
#pragma weak kernel_delete_ipv4 = kernel_add_ipv4
int kernel_add_ipv6 (struct prefix *a, struct rib *b) { return 0; }
#pragma weak kernel_delete_ipv6 = kernel_add_ipv6
-int kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
- unsigned int index, int flags, int table)
-{ return 0; }
+void kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
+ unsigned int index, int table)
+{ }
int kernel_add_route (struct prefix_ipv4 *a, struct in_addr *b, int c, int d)
{ return 0; }
diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c
index e77b9b78..dc298687 100644
--- a/zebra/kernel_socket.c
+++ b/zebra/kernel_socket.c
@@ -161,7 +161,7 @@ const struct message rtm_type_str[] =
{0, NULL}
};
-struct message rtm_flag_str[] =
+static const struct message rtm_flag_str[] =
{
{RTF_UP, "UP"},
{RTF_GATEWAY, "GATEWAY"},
@@ -898,7 +898,7 @@ rtm_read (struct rt_msghdr *rtm)
|| rtm->rtm_type == RTM_ADD
|| rtm->rtm_type == RTM_CHANGE)
rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags,
- &p, &gate.sin.sin_addr, NULL, 0, 0, 0, 0);
+ &p, &gate.sin.sin_addr, NULL, 0, 0, 0, 0, 0, 0);
else
rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags,
&p, &gate.sin.sin_addr, 0, 0);
diff --git a/zebra/main.c b/zebra/main.c
index 61750f1d..209b9044 100644
--- a/zebra/main.c
+++ b/zebra/main.c
@@ -63,12 +63,16 @@ int keep_kernel_mode = 0;
u_int32_t nl_rcvbufsize = 0;
#endif /* HAVE_NETLINK */
+/* Manage connected routes */
+extern int set_interface_mode;
+
/* Command line options. */
struct option longopts[] =
{
{ "batch", no_argument, NULL, 'b'},
{ "daemon", no_argument, NULL, 'd'},
{ "keep_kernel", no_argument, NULL, 'k'},
+ { "set_interface", no_argument, NULL, 'S'},
{ "log_mode", no_argument, NULL, 'l'},
{ "config_file", required_argument, NULL, 'f'},
{ "pid_file", required_argument, NULL, 'i'},
@@ -131,6 +135,7 @@ usage (char *progname, int status)
"-i, --pid_file Set process identifier file name\n"\
"-k, --keep_kernel Don't delete old routes which installed by "\
"zebra.\n"\
+ "-S, --system Manage all routes on link transistions\n"
"-l, --log_mode Set verbose log mode flag\n"\
"-C, --dryrun Check configuration for validity and exit\n"\
"-A, --vty_addr Set vty's bind address\n"\
@@ -231,9 +236,9 @@ main (int argc, char **argv)
int opt;
#ifdef HAVE_NETLINK
- opt = getopt_long (argc, argv, "bdklf:i:hA:P:ru:g:vs:C", longopts, 0);
+ opt = getopt_long (argc, argv, "bdklf:i:hA:P:ru:g:vs:CS", longopts, 0);
#else
- opt = getopt_long (argc, argv, "bdklf:i:hA:P:ru:g:vC", longopts, 0);
+ opt = getopt_long (argc, argv, "bdklf:i:hA:P:ru:g:vCS", longopts, 0);
#endif /* HAVE_NETLINK */
if (opt == EOF)
@@ -251,6 +256,9 @@ main (int argc, char **argv)
case 'k':
keep_kernel_mode = 1;
break;
+ case 'S':
+ set_interface_mode = 1;
+ break;
case 'C':
dryrun = 1;
break;
diff --git a/zebra/redistribute.c b/zebra/redistribute.c
index b7bd5674..a8107aeb 100644
--- a/zebra/redistribute.c
+++ b/zebra/redistribute.c
@@ -369,13 +369,14 @@ zebra_interface_address_add_update (struct interface *ifp,
struct listnode *node, *nnode;
struct zserv *client;
struct prefix *p;
- char buf[BUFSIZ];
if (IS_ZEBRA_DEBUG_EVENT)
{
+ char buf[INET6_ADDRSTRLEN];
+
p = ifc->address;
zlog_debug ("MESSAGE: ZEBRA_INTERFACE_ADDRESS_ADD %s/%d on %s",
- inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
+ inet_ntop (p->family, &p->u.prefix, buf, INET6_ADDRSTRLEN),
p->prefixlen, ifc->ifp->name);
}
@@ -394,13 +395,14 @@ zebra_interface_address_delete_update (struct interface *ifp,
struct listnode *node, *nnode;
struct zserv *client;
struct prefix *p;
- char buf[BUFSIZ];
if (IS_ZEBRA_DEBUG_EVENT)
{
+ char buf[INET6_ADDRSTRLEN];
+
p = ifc->address;
zlog_debug ("MESSAGE: ZEBRA_INTERFACE_ADDRESS_DELETE %s/%d on %s",
- inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
+ inet_ntop (p->family, &p->u.prefix, buf, INET6_ADDRSTRLEN),
p->prefixlen, ifc->ifp->name);
}
diff --git a/zebra/rib.h b/zebra/rib.h
index 887ed3c2..c374df37 100644
--- a/zebra/rib.h
+++ b/zebra/rib.h
@@ -38,10 +38,6 @@ union g_addr {
struct rib
{
- /* Status Flags for the *route_node*, but kept in the head RIB.. */
- u_char rn_status;
-#define RIB_ROUTE_QUEUED(x) (1 << (x))
-
/* Link list. */
struct rib *next;
struct rib *prev;
@@ -49,20 +45,30 @@ struct rib
/* Nexthop structure */
struct nexthop *nexthop;
- /* Refrence count. */
+ /* Reference count. */
unsigned long refcnt;
/* Uptime. */
time_t uptime;
- /* Type fo this route. */
- int type;
+ /* Metric */
+ u_int32_t metric;
/* Which routing table */
- int table;
+ u_int32_t table;
- /* Metric */
- u_int32_t metric;
+ /* Type for this route. < ZEBRA_ROUTE_MAX */
+ u_int8_t type;
+
+ /* Scope for this route: RTM_UNIVERSE .. RTM_NOWHERE */
+ u_int8_t scope;
+
+ /* Routing protocol: RTPROT_UNSPEC .. */
+ u_int8_t protocol;
+
+ /* Status Flags for the *route_node*, but kept in the head RIB.. */
+ u_char rn_status;
+#define RIB_ROUTE_QUEUED(x) (1 << (x))
/* Distance. */
u_char distance;
@@ -104,6 +110,13 @@ struct static_ipv4
struct static_ipv4 *prev;
struct static_ipv4 *next;
+ /* Nexthop value. */
+ union
+ {
+ struct in_addr ipv4;
+ char *ifname;
+ } gate;
+
/* Administrative distance. */
u_char distance;
@@ -113,13 +126,6 @@ struct static_ipv4
#define STATIC_IPV4_IFNAME 2
#define STATIC_IPV4_BLACKHOLE 3
- /* Nexthop value. */
- union
- {
- struct in_addr ipv4;
- char *ifname;
- } gate;
-
/* bit flags */
u_char flags;
/*
@@ -136,6 +142,10 @@ struct static_ipv6
struct static_ipv6 *prev;
struct static_ipv6 *next;
+ /* Nexthop value. */
+ struct in6_addr ipv6;
+ char *ifname;
+
/* Administrative distance. */
u_char distance;
@@ -144,11 +154,6 @@ struct static_ipv6
#define STATIC_IPV6_GATEWAY 1
#define STATIC_IPV6_GATEWAY_IFNAME 2
#define STATIC_IPV6_IFNAME 3
-
- /* Nexthop value. */
- struct in6_addr ipv6;
- char *ifname;
-
/* bit flags */
u_char flags;
/*
@@ -180,22 +185,24 @@ struct nexthop
/* Interface index. */
char *ifname;
unsigned int ifindex;
+
+ /* Nexthop address or interface name. */
+ union g_addr gate;
+
+ unsigned int rifindex;
+ union g_addr rgate;
+ union g_addr src;
- enum nexthop_types_t type;
+/* Really enum nexthop_types_t but safe space */
+ u_char type;
u_char flags;
#define NEXTHOP_FLAG_ACTIVE (1 << 0) /* This nexthop is alive. */
#define NEXTHOP_FLAG_FIB (1 << 1) /* FIB nexthop. */
#define NEXTHOP_FLAG_RECURSIVE (1 << 2) /* Recursive nexthop. */
- /* Nexthop address or interface name. */
- union g_addr gate;
-
/* Recursive lookup nexthop. */
u_char rtype;
- unsigned int rifindex;
- union g_addr rgate;
- union g_addr src;
};
/* Routing table instance. */
@@ -220,7 +227,8 @@ struct vrf
struct route_table *stable[AFI_MAX][SAFI_MAX];
};
-extern struct nexthop *nexthop_ifindex_add (struct rib *, unsigned int);
+extern struct nexthop *nexthop_ifindex_add (struct rib *, unsigned int,
+ struct in_addr *);
extern struct nexthop *nexthop_ifname_add (struct rib *, char *);
extern struct nexthop *nexthop_blackhole_add (struct rib *);
extern struct nexthop *nexthop_ipv4_add (struct rib *, struct in_addr *,
@@ -249,7 +257,8 @@ extern struct route_table *vrf_static_table (afi_t afi, safi_t safi, u_int32_t i
extern int rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p,
struct in_addr *gate, struct in_addr *src,
unsigned int ifindex, u_int32_t vrf_id,
- u_int32_t, u_char);
+ u_int32_t metric, u_int8_t distance,
+ u_int8_t scope, u_int8_t protocol);
extern int rib_add_ipv4_multipath (struct prefix_ipv4 *, struct rib *);
@@ -264,6 +273,8 @@ extern struct rib *rib_lookup_ipv4 (struct prefix_ipv4 *);
extern void rib_update (void);
extern void rib_weed_tables (void);
extern void rib_sweep_route (void);
+struct interface;
+extern void rib_flush_interface (afi_t afi, struct interface *ifp);
extern void rib_close (void);
extern void rib_init (void);
diff --git a/zebra/rt.h b/zebra/rt.h
index 8bfe5a42..8b975558 100644
--- a/zebra/rt.h
+++ b/zebra/rt.h
@@ -36,8 +36,8 @@ extern int kernel_address_delete_ipv4 (struct interface *, struct connected *);
#ifdef HAVE_IPV6
extern int kernel_add_ipv6 (struct prefix *, struct rib *);
extern int kernel_delete_ipv6 (struct prefix *, struct rib *);
-extern int kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
- unsigned int index, int flags, int table);
+extern void kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
+ unsigned int index, int table);
#endif /* HAVE_IPV6 */
diff --git a/zebra/rt_ioctl.c b/zebra/rt_ioctl.c
index a5d588c7..d39ec4df 100644
--- a/zebra/rt_ioctl.c
+++ b/zebra/rt_ioctl.c
@@ -553,8 +553,8 @@ kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
/* Delete IPv6 route from the kernel. */
int
kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
- unsigned int index, int flags, int table)
+ unsigned int index, int table)
{
- return kernel_ioctl_ipv6 (SIOCDELRT, dest, gate, index, flags);
+ return kernel_ioctl_ipv6 (SIOCDELRT, dest, gate, index, 0;
}
#endif /* HAVE_IPV6 */
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index 05254498..2cff4c8c 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -85,32 +85,11 @@ extern struct zebra_privs_t zserv_privs;
extern u_int32_t nl_rcvbufsize;
-/* Note: on netlink systems, there should be a 1-to-1 mapping between interface
- names and ifindex values. */
-static void
-set_ifindex(struct interface *ifp, unsigned int ifi_index)
-{
- struct interface *oifp;
+extern int set_interface_mode;
- if (((oifp = if_lookup_by_index(ifi_index)) != NULL) && (oifp != ifp))
- {
- if (ifi_index == IFINDEX_INTERNAL)
- zlog_err("Netlink is setting interface %s ifindex to reserved "
- "internal value %u", ifp->name, ifi_index);
- else
- {
- if (IS_ZEBRA_DEBUG_KERNEL)
- zlog_debug("interface index %d was renamed from %s to %s",
- ifi_index, oifp->name, ifp->name);
- if (if_is_up(oifp))
- zlog_err("interface rename detected on up interface: index %d "
- "was renamed from %s to %s, results are uncertain!",
- ifi_index, oifp->name, ifp->name);
- if_delete_update(oifp);
- }
- }
- ifp->ifindex = ifi_index;
-}
+static void
+netlink_delroute (int family, void *dest, int length, void *gate,
+ int index, int table, int proto);
static int
netlink_recvbuf (struct nlsock *nl, uint32_t newsize)
@@ -280,7 +259,7 @@ netlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *),
while (1)
{
- char buf[4096];
+ char buf[32768];
struct iovec iov = { buf, sizeof buf };
struct sockaddr_nl snl;
struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 };
@@ -311,6 +290,13 @@ netlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *),
return -1;
}
+ /* JF: Ignore messages that aren't from the kernel */
+ if ( snl.nl_pid != 0 )
+ {
+ zlog ( NULL, LOG_ERR, "Ignoring message from pid %u", snl.nl_pid );
+ continue;
+ }
+
for (h = (struct nlmsghdr *) buf; NLMSG_OK (h, (unsigned int) status);
h = NLMSG_NEXT (h, status))
{
@@ -462,14 +448,23 @@ netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h)
#endif /* IFLA_WIRELESS */
if (tb[IFLA_IFNAME] == NULL)
- return -1;
+ {
+ zlog_err("%s: missing interface name in message", __func__);
+ return -1;
+ }
name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
+ if (ifi->ifi_index == IFINDEX_INTERNAL)
+ {
+ zlog_err("%s: reserved ifindex", __func__);
+ return -1;
+ }
+
/* Add interface. */
ifp = if_get_by_name (name);
- set_ifindex(ifp, ifi->ifi_index);
+ ifp->ifindex = ifi->ifi_index;
ifp->flags = ifi->ifi_flags & 0x0000fffff;
- ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
+ ifp->mtu6 = ifp->mtu = *(uint32_t *) RTA_DATA (tb[IFLA_MTU]);
ifp->metric = 1;
/* Hardware type and address. */
@@ -523,7 +518,7 @@ netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h)
#ifdef HAVE_IPV6
&& ifa->ifa_family != AF_INET6
#endif /* HAVE_IPV6 */
- )
+ )
return 0;
if (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR)
@@ -539,6 +534,9 @@ netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h)
ifp = if_lookup_by_index (ifa->ifa_index);
if (ifp == NULL)
{
+ if (h->nlmsg_type == RTM_DELADDR)
+ return 0;
+
zlog_err ("netlink_interface_addr can't find interface by index %d",
ifa->ifa_index);
return -1;
@@ -548,7 +546,7 @@ netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h)
{
char buf[BUFSIZ];
zlog_debug ("netlink_interface_addr %s %s:",
- lookup (nlmsg_str, h->nlmsg_type), ifp->name);
+ lookup (nlmsg_str, h->nlmsg_type), ifp->name);
if (tb[IFA_LOCAL])
zlog_debug (" IFA_LOCAL %s/%d",
inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_LOCAL]),
@@ -614,9 +612,25 @@ netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h)
if (ifa->ifa_family == AF_INET)
{
if (h->nlmsg_type == RTM_NEWADDR)
- connected_add_ipv4 (ifp, flags,
- (struct in_addr *) addr, ifa->ifa_prefixlen,
- (struct in_addr *) broad, label);
+ {
+ struct connected *ifc;
+ ifc = connected_add_ipv4 (ifp, flags,
+ (struct in_addr *) addr, ifa->ifa_prefixlen,
+ (struct in_addr *) broad, label);
+
+ /* If address added, but interface is down,
+ then remove the FIB entry from kernel.
+ */
+ if (set_interface_mode && ifc && !if_is_operative (ifp))
+ {
+ struct prefix_ipv4 p;
+ PREFIX_COPY_IPV4(&p, CONNECTED_PREFIX(ifc));
+ apply_mask_ipv4 (&p);
+
+ netlink_delroute (p.family, &p.prefix, p.prefixlen, NULL,
+ ifp->ifindex, RT_TABLE_MAIN, RTPROT_KERNEL);
+ }
+ }
else
connected_delete_ipv4 (ifp, flags,
(struct in_addr *) addr, ifa->ifa_prefixlen,
@@ -626,9 +640,9 @@ netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h)
if (ifa->ifa_family == AF_INET6)
{
if (h->nlmsg_type == RTM_NEWADDR)
- connected_add_ipv6 (ifp, flags,
- (struct in6_addr *) addr, ifa->ifa_prefixlen,
- (struct in6_addr *) broad, label);
+ connected_add_ipv6 (ifp, flags,
+ (struct in6_addr *) addr, ifa->ifa_prefixlen,
+ (struct in6_addr *) broad, label);
else
connected_delete_ipv6 (ifp,
(struct in6_addr *) addr, ifa->ifa_prefixlen,
@@ -652,7 +666,7 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h)
int index;
int table;
- int metric;
+ u_int32_t metric;
void *dest;
void *gate;
@@ -682,6 +696,7 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h)
return 0;
if (rtm->rtm_protocol == RTPROT_REDIRECT)
return 0;
+
if (rtm->rtm_protocol == RTPROT_KERNEL)
return 0;
@@ -699,7 +714,7 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h)
src = NULL;
if (tb[RTA_OIF])
- index = *(int *) RTA_DATA (tb[RTA_OIF]);
+ index = *(uint32_t *) RTA_DATA (tb[RTA_OIF]);
if (tb[RTA_DST])
dest = RTA_DATA (tb[RTA_DST]);
@@ -714,7 +729,7 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h)
gate = RTA_DATA (tb[RTA_GATEWAY]);
if (tb[RTA_PRIORITY])
- metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]);
+ metric = *(uint32_t *) RTA_DATA(tb[RTA_PRIORITY]);
if (rtm->rtm_family == AF_INET)
{
@@ -723,7 +738,8 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h)
memcpy (&p.prefix, dest, 4);
p.prefixlen = rtm->rtm_dst_len;
- rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, src, index, table, metric, 0);
+ rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, src, index,
+ table, metric, 0, rtm->rtm_scope, rtm->rtm_protocol);
}
#ifdef HAVE_IPV6
if (rtm->rtm_family == AF_INET6)
@@ -768,6 +784,8 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
int index;
int table;
+ u_int32_t metric;
+
void *dest;
void *gate;
void *src;
@@ -781,33 +799,35 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
return 0;
}
+ len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
+ if (len < 0)
+ return -1;
+
+ memset (tb, 0, sizeof tb);
+ netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
+
+ if (tb[RTA_DST])
+ dest = RTA_DATA (tb[RTA_DST]);
+ else
+ dest = anyaddr;
+
/* Connected route. */
if (IS_ZEBRA_DEBUG_KERNEL)
- zlog_debug ("%s %s %s proto %s",
- h->nlmsg_type ==
- RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE",
- rtm->rtm_family == AF_INET ? "ipv4" : "ipv6",
- rtm->rtm_type == RTN_UNICAST ? "unicast" : "multicast",
- lookup (rtproto_str, rtm->rtm_protocol));
+ {
+ char buf[INET6_ADDRSTRLEN];
+ zlog_debug ("%s %s %s proto %s",
+ h->nlmsg_type == RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE",
+ inet_ntop(rtm->rtm_family, dest, buf, sizeof(buf)),
+ rtm->rtm_type == RTN_UNICAST ? "unicast" : "multicast",
+ lookup (rtproto_str, rtm->rtm_protocol));
+ }
if (rtm->rtm_type != RTN_UNICAST)
- {
return 0;
- }
table = rtm->rtm_table;
if (table != RT_TABLE_MAIN && table != zebrad.rtm_table_default)
- {
return 0;
- }
-
- len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
- if (len < 0)
- return -1;
-
- memset (tb, 0, sizeof tb);
- netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
-
if (rtm->rtm_flags & RTM_F_CLONED)
return 0;
if (rtm->rtm_protocol == RTPROT_REDIRECT)
@@ -825,17 +845,12 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
}
index = 0;
- dest = NULL;
+ metric = 0;
gate = NULL;
src = NULL;
if (tb[RTA_OIF])
- index = *(int *) RTA_DATA (tb[RTA_OIF]);
-
- if (tb[RTA_DST])
- dest = RTA_DATA (tb[RTA_DST]);
- else
- dest = anyaddr;
+ index = *(uint32_t *) RTA_DATA (tb[RTA_OIF]);
if (tb[RTA_GATEWAY])
gate = RTA_DATA (tb[RTA_GATEWAY]);
@@ -843,6 +858,9 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
if (tb[RTA_PREFSRC])
src = RTA_DATA (tb[RTA_PREFSRC]);
+ if (tb[RTA_PRIORITY])
+ metric = *(uint32_t *) RTA_DATA(tb[RTA_PRIORITY]);
+
if (rtm->rtm_family == AF_INET)
{
struct prefix_ipv4 p;
@@ -850,18 +868,9 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
memcpy (&p.prefix, dest, 4);
p.prefixlen = rtm->rtm_dst_len;
- if (IS_ZEBRA_DEBUG_KERNEL)
- {
- if (h->nlmsg_type == RTM_NEWROUTE)
- zlog_debug ("RTM_NEWROUTE %s/%d",
- inet_ntoa (p.prefix), p.prefixlen);
- else
- zlog_debug ("RTM_DELROUTE %s/%d",
- inet_ntoa (p.prefix), p.prefixlen);
- }
-
if (h->nlmsg_type == RTM_NEWROUTE)
- rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, table, 0, 0);
+ rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, table,
+ metric, 0, rtm->rtm_scope, rtm->rtm_protocol);
else
rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table);
}
@@ -870,26 +879,13 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
if (rtm->rtm_family == AF_INET6)
{
struct prefix_ipv6 p;
- char buf[BUFSIZ];
p.family = AF_INET6;
memcpy (&p.prefix, dest, 16);
p.prefixlen = rtm->rtm_dst_len;
- if (IS_ZEBRA_DEBUG_KERNEL)
- {
- if (h->nlmsg_type == RTM_NEWROUTE)
- zlog_debug ("RTM_NEWROUTE %s/%d",
- inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
- p.prefixlen);
- else
- zlog_debug ("RTM_DELROUTE %s/%d",
- inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
- p.prefixlen);
- }
-
if (h->nlmsg_type == RTM_NEWROUTE)
- rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0, 0, 0);
+ rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0, metric, 0);
else
rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0);
}
@@ -919,7 +915,10 @@ netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
if (len < 0)
- return -1;
+ {
+ zlog_err ("%s: truncated netlink message", __func__);
+ return -1;
+ }
/* Looking up interface name. */
memset (tb, 0, sizeof tb);
@@ -936,62 +935,96 @@ netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
#endif /* IFLA_WIRELESS */
if (tb[IFLA_IFNAME] == NULL)
- return -1;
+ {
+ zlog_err("%s: missing interface name", __func__);
+ return -1;
+ }
name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
/* Add interface. */
if (h->nlmsg_type == RTM_NEWLINK)
{
- ifp = if_lookup_by_name (name);
+ unsigned long new_flags = ifi->ifi_flags & 0x0000fffff;
+ unsigned int mtu = *(uint32_t *) RTA_DATA (tb[IFLA_MTU]);
+
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug ("%s: new link flags %#lx mtu %d", __func__, new_flags, mtu);
+ ifp = if_lookup_by_index (ifi->ifi_index);
if (ifp == NULL || !CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
{
if (ifp == NULL)
- ifp = if_get_by_name (name);
+ {
+ ifp = if_get_by_name (name);
+ ifp->ifindex = ifi->ifi_index;
+ ifp->metric = 1;
+ }
+
+ zlog_info ("interface %s index %d %s added.",
+ name, ifi->ifi_index, if_flag_dump(new_flags));
- set_ifindex(ifp, ifi->ifi_index);
- ifp->flags = ifi->ifi_flags & 0x0000fffff;
- ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
- ifp->metric = 1;
+ ifp->flags = new_flags;
+ ifp->mtu6 = ifp->mtu = mtu;
/* If new link is added. */
if_add_update (ifp);
}
- else
- {
- /* Interface status change. */
- set_ifindex(ifp, ifi->ifi_index);
- ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
- ifp->metric = 1;
-
- if (if_is_operative (ifp))
- {
- ifp->flags = ifi->ifi_flags & 0x0000fffff;
- if (!if_is_operative (ifp))
- if_down (ifp);
+ /* Interface status change. */
+ else if (new_flags != ifp->flags)
+ {
+ ifp->mtu6 = ifp->mtu = mtu;
+
+ zlog_info ("interface %s index %d changed %s.",
+ name, ifi->ifi_index, if_flag_dump(new_flags));
+
+ if (if_is_operative (ifp))
+ {
+ ifp->flags = new_flags;
+ if (!if_is_operative (ifp))
+ if_down (ifp);
else
/* Must notify client daemons of new interface status. */
- zebra_interface_up_update (ifp);
- }
- else
- {
- ifp->flags = ifi->ifi_flags & 0x0000fffff;
- if (if_is_operative (ifp))
- if_up (ifp);
- }
- }
+ zebra_interface_up_update (ifp);
+ }
+ else
+ {
+ ifp->flags = new_flags;
+ if (if_is_operative (ifp))
+ if_up (ifp);
+ }
+ }
+ /* Interface name change */
+ else if (strcmp(ifp->name, name) != 0)
+ {
+ ifp->mtu = ifp->mtu6 = mtu;
+ zlog_info("interface index %d was renamed from %s to %s",
+ ifi->ifi_index, ifp->name, name);
+
+ if_rename (ifp, name);
+ }
+ /* Interface mtu change */
+ else if (mtu != ifp->mtu)
+ {
+ zlog_info("interface %s mtu changed from %u to %u",
+ ifp->name, ifp->mtu, mtu);
+ ifp->mtu = ifp->mtu6 = mtu;
+ if (if_is_operative (ifp))
+ zebra_interface_up_update (ifp);
+ }
}
else
{
- /* RTM_DELLINK. */
- ifp = if_lookup_by_name (name);
-
+ // RTM_DELLINK.
+ ifp = if_lookup_by_index (ifi->ifi_index);
if (ifp == NULL)
{
- zlog (NULL, LOG_WARNING, "interface %s is deleted but can't find",
- name);
+ zlog (NULL, LOG_WARNING, "interface %s index %d is deleted but can't find",
+ name, ifi->ifi_index);
return 0;
}
+ else
+ zlog_info ("interface %s index %d deleted.",
+ name, ifi->ifi_index);
if_delete_update (ifp);
}
@@ -1002,13 +1035,6 @@ netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
static int
netlink_information_fetch (struct sockaddr_nl *snl, struct nlmsghdr *h)
{
- /* JF: Ignore messages that aren't from the kernel */
- if ( snl->nl_pid != 0 )
- {
- zlog ( NULL, LOG_ERR, "Ignoring message from pid %u", snl->nl_pid );
- return 0;
- }
-
switch (h->nlmsg_type)
{
case RTM_NEWROUTE:
@@ -1188,11 +1214,6 @@ netlink_talk (struct nlmsghdr *n, struct nlsock *nl)
/* Request an acknowledgement by setting NLM_F_ACK */
n->nlmsg_flags |= NLM_F_ACK;
- if (IS_ZEBRA_DEBUG_KERNEL)
- zlog_debug ("netlink_talk: %s type %s(%u), seq=%u", nl->name,
- lookup (nlmsg_str, n->nlmsg_type), n->nlmsg_type,
- n->nlmsg_seq);
-
/* Send message to netlink interface. */
if (zserv_privs.change (ZPRIVS_RAISE))
zlog (NULL, LOG_ERR, "Can't raise privileges");
@@ -1217,15 +1238,11 @@ netlink_talk (struct nlmsghdr *n, struct nlsock *nl)
}
/* Routing table change via netlink interface. */
-static int
-netlink_route (int cmd, int family, void *dest, int length, void *gate,
- int index, int zebra_flags, int table)
+static void
+netlink_delroute (int family, void *dest, int length, void *gate,
+ int index, int table, int proto)
{
- int ret;
- int bytelen;
- struct sockaddr_nl snl;
- int discard;
-
+ int bytelen = (family == AF_INET ? 4 : 16);
struct
{
struct nlmsghdr n;
@@ -1235,59 +1252,26 @@ netlink_route (int cmd, int family, void *dest, int length, void *gate,
memset (&req, 0, sizeof req);
- bytelen = (family == AF_INET ? 4 : 16);
-
req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
- req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
- req.n.nlmsg_type = cmd;
+ req.n.nlmsg_flags = NLM_F_REQUEST;
+ req.n.nlmsg_type = RTM_DELROUTE;
req.r.rtm_family = family;
- req.r.rtm_table = table;
req.r.rtm_dst_len = length;
- req.r.rtm_protocol = RTPROT_ZEBRA;
- req.r.rtm_scope = RT_SCOPE_UNIVERSE;
-
- if ((zebra_flags & ZEBRA_FLAG_BLACKHOLE)
- || (zebra_flags & ZEBRA_FLAG_REJECT))
- discard = 1;
- else
- discard = 0;
-
- if (cmd == RTM_NEWROUTE)
- {
- if (discard)
- {
- if (zebra_flags & ZEBRA_FLAG_BLACKHOLE)
- req.r.rtm_type = RTN_BLACKHOLE;
- else if (zebra_flags & ZEBRA_FLAG_REJECT)
- req.r.rtm_type = RTN_UNREACHABLE;
- else
- assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */
- }
- else
- req.r.rtm_type = RTN_UNICAST;
- }
+ req.r.rtm_scope = RT_SCOPE_NOWHERE;
+ req.r.rtm_protocol = RTPROT_UNSPEC;
+ req.r.rtm_table = table;
if (dest)
addattr_l (&req.n, sizeof req, RTA_DST, dest, bytelen);
- if (!discard)
- {
- if (gate)
- addattr_l (&req.n, sizeof req, RTA_GATEWAY, gate, bytelen);
- if (index > 0)
- addattr32 (&req.n, sizeof req, RTA_OIF, index);
- }
+ if (gate)
+ addattr_l (&req.n, sizeof req, RTA_GATEWAY, gate, bytelen);
- /* Destination netlink address. */
- memset (&snl, 0, sizeof snl);
- snl.nl_family = AF_NETLINK;
+ if (index > 0)
+ addattr32 (&req.n, sizeof req, RTA_OIF, index);
/* Talk to netlink socket. */
- ret = netlink_talk (&req.n, &netlink_cmd);
- if (ret < 0)
- return -1;
-
- return 0;
+ netlink_talk (&req.n, &netlink_cmd);
}
/* Routing table change via netlink interface. */
@@ -1318,14 +1302,24 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
req.r.rtm_family = family;
req.r.rtm_table = rib->table;
req.r.rtm_dst_len = p->prefixlen;
- req.r.rtm_protocol = RTPROT_ZEBRA;
- req.r.rtm_scope = RT_SCOPE_UNIVERSE;
+ req.r.rtm_scope = rib->scope;
if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) || (rib->flags & ZEBRA_FLAG_REJECT))
discard = 1;
else
discard = 0;
+ switch (rib->type) {
+ case ZEBRA_ROUTE_KERNEL:
+ req.r.rtm_protocol = rib->protocol;
+ break;
+ case ZEBRA_ROUTE_CONNECT:
+ req.r.rtm_protocol = RTPROT_KERNEL;
+ break;
+ default:
+ req.r.rtm_protocol = RTPROT_ZEBRA;
+ }
+
if (cmd == RTM_NEWROUTE)
{
if (discard)
@@ -1343,8 +1337,8 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
addattr_l (&req.n, sizeof req, RTA_DST, &p->u.prefix, bytelen);
- /* Metric. */
- addattr32 (&req.n, sizeof req, RTA_PRIORITY, rib->metric);
+ if (rib->type != ZEBRA_ROUTE_CONNECT)
+ addattr32 (&req.n, sizeof req, RTA_PRIORITY, rib->metric);
if (discard)
{
@@ -1743,12 +1737,12 @@ kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
}
/* Delete IPv6 route from the kernel. */
-int
+void
kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
- unsigned int index, int flags, int table)
+ unsigned int index, int table)
{
- return netlink_route (RTM_DELROUTE, AF_INET6, &dest->prefix,
- dest->prefixlen, gate, index, flags, table);
+ netlink_delroute (AF_INET6, &dest->prefix,
+ dest->prefixlen, gate, index, table, RTPROT_ZEBRA);
}
#endif /* HAVE_IPV6 */
@@ -1837,19 +1831,13 @@ kernel_read (struct thread *thread)
static void netlink_install_filter (int sock, __u32 pid)
{
struct sock_filter filter[] = {
- /* 0: ldh [4] */
- BPF_STMT(BPF_LD|BPF_ABS|BPF_H, offsetof(struct nlmsghdr, nlmsg_type)),
- /* 1: jeq 0x18 jt 3 jf 6 */
- BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_NEWROUTE), 1, 0),
- /* 2: jeq 0x19 jt 3 jf 6 */
- BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_DELROUTE), 0, 3),
- /* 3: ldw [12] */
+ /* 0: ldw [12] */
BPF_STMT(BPF_LD|BPF_ABS|BPF_W, offsetof(struct nlmsghdr, nlmsg_pid)),
- /* 4: jeq XX jt 5 jf 6 */
+ /* 1: jeq XX jt 2 jf 3 */
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htonl(pid), 0, 1),
- /* 5: ret 0 (skip) */
+ /* 2: ret 0 (skip) */
BPF_STMT(BPF_RET|BPF_K, 0),
- /* 6: ret 0xffff (keep) */
+ /* 3: ret 0xffff (keep) */
BPF_STMT(BPF_RET|BPF_K, 0xffff),
};
diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c
index 1b8ded7e..9bbecb95 100644
--- a/zebra/rt_socket.c
+++ b/zebra/rt_socket.c
@@ -509,13 +509,13 @@ kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
/* Delete IPv6 route from the kernel. */
int
kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
- unsigned int index, int flags, int table)
+ unsigned int index, int table)
{
int route;
if (zserv_privs.change(ZPRIVS_RAISE))
zlog (NULL, LOG_ERR, "Can't raise privileges");
- route = kernel_rtm_ipv6 (RTM_DELETE, dest, gate, index, flags);
+ route = kernel_rtm_ipv6 (RTM_DELETE, dest, gate, index);
if (zserv_privs.change(ZPRIVS_LOWER))
zlog (NULL, LOG_ERR, "Can't lower privileges");
diff --git a/zebra/rtadv.c b/zebra/rtadv.c
index 4bdb83d5..0feb850a 100644
--- a/zebra/rtadv.c
+++ b/zebra/rtadv.c
@@ -84,17 +84,16 @@ struct rtadv *rtadv = NULL;
static struct rtadv *
rtadv_new (void)
{
- struct rtadv *new;
- new = XMALLOC (MTYPE_TMP, sizeof (struct rtadv));
- memset (new, 0, sizeof (struct rtadv));
- return new;
+ return XCALLOC (MTYPE_TMP, sizeof (struct rtadv));
}
+#if 0
static void
rtadv_free (struct rtadv *rtadv)
{
XFREE (MTYPE_TMP, rtadv);
}
+#endif
static int
rtadv_recv_packet (int sock, u_char *buf, int buflen,
@@ -209,7 +208,12 @@ rtadv_send_packet (int sock, struct interface *ifp)
rtadv->nd_ra_cksum = 0;
rtadv->nd_ra_curhoplimit = 64;
- rtadv->nd_ra_flags_reserved = 0;
+
+ /* RFC4191: Default Router Preference is 0 if Router Lifetime is 0. */
+ rtadv->nd_ra_flags_reserved =
+ zif->rtadv.AdvDefaultLifetime == 0 ? 0 : zif->rtadv.DefaultPreference;
+ rtadv->nd_ra_flags_reserved <<= 3;
+
if (zif->rtadv.AdvManagedFlag)
rtadv->nd_ra_flags_reserved |= ND_RA_FLAG_MANAGED;
if (zif->rtadv.AdvOtherConfigFlag)
@@ -451,7 +455,7 @@ rtadv_read (struct thread *thread)
int len;
u_char buf[RTADV_MSG_SIZE];
struct sockaddr_in6 from;
- unsigned int ifindex;
+ unsigned int ifindex = 0;
int hoplimit = -1;
sock = THREAD_FD (thread);
@@ -527,14 +531,9 @@ rtadv_make_socket (void)
}
static struct rtadv_prefix *
-rtadv_prefix_new ()
+rtadv_prefix_new (void)
{
- struct rtadv_prefix *new;
-
- new = XMALLOC (MTYPE_RTADV_PREFIX, sizeof (struct rtadv_prefix));
- memset (new, 0, sizeof (struct rtadv_prefix));
-
- return new;
+ return XCALLOC (MTYPE_RTADV_PREFIX, sizeof (struct rtadv_prefix));
}
static void
@@ -1372,6 +1371,56 @@ DEFUN (no_ipv6_nd_prefix,
return CMD_SUCCESS;
}
+
+DEFUN (ipv6_nd_router_preference,
+ ipv6_nd_router_preference_cmd,
+ "ipv6 nd router-preference (high|medium|low)",
+ "Interface IPv6 config commands\n"
+ "Neighbor discovery\n"
+ "Default router preference\n"
+ "High default router preference\n"
+ "Low default router preference\n"
+ "Medium default router preference (default)\n")
+{
+ struct interface *ifp;
+ struct zebra_if *zif;
+ int i = 0;
+
+ ifp = (struct interface *) vty->index;
+ zif = ifp->info;
+
+ while (0 != rtadv_pref_strs[i])
+ {
+ if (strncmp (argv[0], rtadv_pref_strs[i], 1) == 0)
+ {
+ zif->rtadv.DefaultPreference = i;
+ return CMD_SUCCESS;
+ }
+ i++;
+ }
+
+ return CMD_ERR_NO_MATCH;
+}
+
+DEFUN (no_ipv6_nd_router_preference,
+ no_ipv6_nd_router_preference_cmd,
+ "no ipv6 nd router-preference",
+ NO_STR
+ "Interface IPv6 config commands\n"
+ "Neighbor discovery\n"
+ "Default router preference\n")
+{
+ struct interface *ifp;
+ struct zebra_if *zif;
+
+ ifp = (struct interface *) vty->index;
+ zif = ifp->info;
+
+ zif->rtadv.DefaultPreference = RTADV_PREF_MEDIUM; /* Default per RFC4191. */
+
+ return CMD_SUCCESS;
+}
+
/* Write configuration about router advertisement. */
void
rtadv_config_write (struct vty *vty, struct interface *ifp)
@@ -1419,6 +1468,11 @@ rtadv_config_write (struct vty *vty, struct interface *ifp)
if (zif->rtadv.AdvOtherConfigFlag)
vty_out (vty, " ipv6 nd other-config-flag%s", VTY_NEWLINE);
+ if (zif->rtadv.DefaultPreference != RTADV_PREF_MEDIUM)
+ vty_out (vty, " ipv6 nd router-preference %s%s",
+ rtadv_pref_strs[zif->rtadv.DefaultPreference],
+ VTY_NEWLINE);
+
for (ALL_LIST_ELEMENTS_RO (zif->rtadv.AdvPrefixList, node, rprefix))
{
vty_out (vty, " ipv6 nd prefix %s/%d",
@@ -1540,6 +1594,8 @@ rtadv_init (void)
install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_rtaddr_cmd);
install_element (INTERFACE_NODE, &ipv6_nd_prefix_prefix_cmd);
install_element (INTERFACE_NODE, &no_ipv6_nd_prefix_cmd);
+ install_element (INTERFACE_NODE, &ipv6_nd_router_preference_cmd);
+ install_element (INTERFACE_NODE, &no_ipv6_nd_router_preference_cmd);
}
static int
diff --git a/zebra/rtadv.h b/zebra/rtadv.h
index abd1c6fc..d8d263d0 100644
--- a/zebra/rtadv.h
+++ b/zebra/rtadv.h
@@ -94,4 +94,6 @@ struct nd_opt_homeagent_info { /* Home Agent info */
} __attribute__((__packed__));
#endif
+extern const char *rtadv_pref_strs[];
+
#endif /* _ZEBRA_RTADV_H */
diff --git a/zebra/rtread_getmsg.c b/zebra/rtread_getmsg.c
index 3e065c6f..2978ae11 100644
--- a/zebra/rtread_getmsg.c
+++ b/zebra/rtread_getmsg.c
@@ -90,7 +90,7 @@ handle_route_entry (mib2_ipRouteEntry_t *routeEntry)
gateway.s_addr = routeEntry->ipRouteNextHop;
rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &prefix,
- &gateway, NULL, 0, 0, 0, 0);
+ &gateway, NULL, 0, 0, 0, 0, 0, 0);
}
void
diff --git a/zebra/rtread_netlink.c b/zebra/rtread_netlink.c
index 0b255a53..44715d94 100644
--- a/zebra/rtread_netlink.c
+++ b/zebra/rtread_netlink.c
@@ -21,11 +21,9 @@
*/
#include <zebra.h>
+extern void netlink_route_read (void);
-/* Extern from rt_netlink.c */
-void netlink_route_read ();
-
-void route_read ()
+void route_read (void)
{
netlink_route_read ();
}
diff --git a/zebra/rtread_proc.c b/zebra/rtread_proc.c
index 1de435a4..4f246de9 100644
--- a/zebra/rtread_proc.c
+++ b/zebra/rtread_proc.c
@@ -96,7 +96,8 @@ proc_route_read (void)
p.prefixlen = ip_masklen (tmpmask);
sscanf (gate, "%lX", (unsigned long *)&gateway);
- rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gateway, NULL, 0, 0, 0, 0);
+ rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gateway, NULL,
+ 0, 0, 0, 0, 0, 0);
}
fclose (fp);
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index 90db932b..ade13578 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -44,6 +44,9 @@
/* Default rtm_table for all clients */
extern struct zebra_t zebrad;
+/* Should kernel routes be removed on link down? */
+int set_interface_mode;
+
/* Hold time for RIB process, should be very minimal.
* it is useful to able to set it otherwise for testing, hence exported
* as global here for test-rig code.
@@ -93,6 +96,7 @@ vrf_alloc (const char *name)
return vrf;
}
+#if 0
/* Free VRF. */
static void
vrf_free (struct vrf *vrf)
@@ -101,6 +105,7 @@ vrf_free (struct vrf *vrf)
XFREE (MTYPE_VRF_NAME, vrf->name);
XFREE (MTYPE_VRF, vrf);
}
+#endif
/* Lookup VRF by identifier. */
struct vrf *
@@ -109,6 +114,7 @@ vrf_lookup (u_int32_t id)
return vector_lookup (vrf_vector, id);
}
+#if 0
/* Lookup VRF by name. */
static struct vrf *
vrf_lookup_by_name (char *name)
@@ -122,6 +128,7 @@ vrf_lookup_by_name (char *name)
return vrf;
return NULL;
}
+#endif
/* Initialize VRF. */
static void
@@ -205,14 +212,16 @@ nexthop_free (struct nexthop *nexthop)
}
struct nexthop *
-nexthop_ifindex_add (struct rib *rib, unsigned int ifindex)
+nexthop_ifindex_add (struct rib *rib, unsigned int ifindex,
+ struct in_addr *src)
{
struct nexthop *nexthop;
- nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
- memset (nexthop, 0, sizeof (struct nexthop));
+ nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
nexthop->type = NEXTHOP_TYPE_IFINDEX;
nexthop->ifindex = ifindex;
+ if (src)
+ nexthop->src.ipv4 = *src;
nexthop_add (rib, nexthop);
@@ -224,8 +233,7 @@ nexthop_ifname_add (struct rib *rib, char *ifname)
{
struct nexthop *nexthop;
- nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
- memset (nexthop, 0, sizeof (struct nexthop));
+ nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
nexthop->type = NEXTHOP_TYPE_IFNAME;
nexthop->ifname = XSTRDUP (0, ifname);
@@ -239,8 +247,7 @@ nexthop_ipv4_add (struct rib *rib, struct in_addr *ipv4, struct in_addr *src)
{
struct nexthop *nexthop;
- nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
- memset (nexthop, 0, sizeof (struct nexthop));
+ nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
nexthop->type = NEXTHOP_TYPE_IPV4;
nexthop->gate.ipv4 = *ipv4;
if (src)
@@ -257,8 +264,7 @@ nexthop_ipv4_ifindex_add (struct rib *rib, struct in_addr *ipv4,
{
struct nexthop *nexthop;
- nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
- memset (nexthop, 0, sizeof (struct nexthop));
+ nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
nexthop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
nexthop->gate.ipv4 = *ipv4;
if (src)
@@ -276,8 +282,7 @@ nexthop_ipv6_add (struct rib *rib, struct in6_addr *ipv6)
{
struct nexthop *nexthop;
- nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
- memset (nexthop, 0, sizeof (struct nexthop));
+ nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
nexthop->type = NEXTHOP_TYPE_IPV6;
nexthop->gate.ipv6 = *ipv6;
@@ -292,8 +297,7 @@ nexthop_ipv6_ifname_add (struct rib *rib, struct in6_addr *ipv6,
{
struct nexthop *nexthop;
- nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
- memset (nexthop, 0, sizeof (struct nexthop));
+ nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
nexthop->type = NEXTHOP_TYPE_IPV6_IFNAME;
nexthop->gate.ipv6 = *ipv6;
nexthop->ifname = XSTRDUP (0, ifname);
@@ -309,8 +313,7 @@ nexthop_ipv6_ifindex_add (struct rib *rib, struct in6_addr *ipv6,
{
struct nexthop *nexthop;
- nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
- memset (nexthop, 0, sizeof (struct nexthop));
+ nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
nexthop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
nexthop->gate.ipv6 = *ipv6;
nexthop->ifindex = ifindex;
@@ -326,8 +329,7 @@ nexthop_blackhole_add (struct rib *rib)
{
struct nexthop *nexthop;
- nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
- memset (nexthop, 0, sizeof (struct nexthop));
+ nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
nexthop->type = NEXTHOP_TYPE_BLACKHOLE;
SET_FLAG (rib->flags, ZEBRA_FLAG_BLACKHOLE);
@@ -336,6 +338,35 @@ nexthop_blackhole_add (struct rib *rib)
return nexthop;
}
+static int
+nexthop_isactive(const struct nexthop *nexthop)
+{
+ struct interface *ifp;
+
+ switch(nexthop->type)
+ {
+ case NEXTHOP_TYPE_IPV4:
+ case NEXTHOP_TYPE_IPV6:
+ if (nexthop->ifindex == 0)
+ return 0;
+ /* fall through */
+ case NEXTHOP_TYPE_IFINDEX:
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ ifp = if_lookup_by_index (nexthop->ifindex);
+ return (ifp && if_is_operative (ifp));
+
+ case NEXTHOP_TYPE_IFNAME:
+ case NEXTHOP_TYPE_IPV4_IFNAME:
+ case NEXTHOP_TYPE_IPV6_IFNAME:
+ ifp = if_lookup_by_name(nexthop->ifname);
+ return (ifp && if_is_operative (ifp));
+
+ default:
+ return 1;
+ }
+}
+
/* If force flag is not set, do not modify falgs at all for uninstall
the route from FIB. */
static int
@@ -348,11 +379,12 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set,
struct rib *match;
struct nexthop *newhop;
- if (nexthop->type == NEXTHOP_TYPE_IPV4)
- nexthop->ifindex = 0;
-
if (set)
- UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
+ {
+ UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
+ if (nexthop->type == NEXTHOP_TYPE_IPV4)
+ nexthop->ifindex = 0;
+ }
/* Make lookup prefix. */
memset (&p, 0, sizeof (struct prefix_ipv4));
@@ -400,16 +432,31 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set,
{
/* Directly point connected route. */
newhop = match->nexthop;
- if (newhop && nexthop->type == NEXTHOP_TYPE_IPV4)
- nexthop->ifindex = newhop->ifindex;
-
- return 1;
+ if (!newhop)
+ return 0; /* dead route */
+
+ if (nexthop_isactive (newhop))
+ {
+ if (set)
+ {
+ if (nexthop->type == NEXTHOP_TYPE_IPV4)
+ nexthop->ifindex = newhop->ifindex;
+ }
+ else
+ {
+ if (nexthop->ifindex != newhop->ifindex ||
+ CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
+ SET_FLAG (rib->flags, ZEBRA_FLAG_CHANGED);
+ }
+ return 1;
+ }
}
else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL))
{
for (newhop = match->nexthop; newhop; newhop = newhop->next)
if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB)
- && ! CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_RECURSIVE))
+ && ! CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_RECURSIVE)
+ && nexthop_isactive (newhop))
{
if (set)
{
@@ -422,7 +469,24 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set,
|| newhop->type == NEXTHOP_TYPE_IFNAME
|| newhop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
nexthop->rifindex = newhop->ifindex;
+ if (nexthop->type == NEXTHOP_TYPE_IPV4)
+ nexthop->ifindex = newhop->ifindex;
+ }
+ else if (! CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)
+ || nexthop->rtype != newhop->type
+ || ((newhop->type == NEXTHOP_TYPE_IPV4 ||
+ newhop->type == NEXTHOP_TYPE_IPV4_IFINDEX) &&
+ nexthop->gate.ipv4.s_addr != newhop->gate.ipv4.s_addr)
+ || ((newhop->type == NEXTHOP_TYPE_IFINDEX
+ || newhop->type == NEXTHOP_TYPE_IFNAME
+ || newhop->type == NEXTHOP_TYPE_IPV4_IFINDEX) &&
+ nexthop->rifindex != newhop->ifindex)
+ || ((nexthop->type == NEXTHOP_TYPE_IPV4) &&
+ nexthop->ifindex != newhop->ifindex))
+ {
+ SET_FLAG (rib->flags, ZEBRA_FLAG_CHANGED);
}
+
return 1;
}
return 0;
@@ -501,17 +565,35 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set,
{
/* Directly point connected route. */
newhop = match->nexthop;
+ if (!newhop)
+ return 0; /* dead route */
- if (newhop && nexthop->type == NEXTHOP_TYPE_IPV6)
+ /* recursive route, remember index */
+ if (nexthop->type == NEXTHOP_TYPE_IPV6)
nexthop->ifindex = newhop->ifindex;
- return 1;
+ if (nexthop_isactive (newhop))
+ {
+ if (set)
+ {
+ if (nexthop->type == NEXTHOP_TYPE_IPV6)
+ nexthop->ifindex = newhop->ifindex;
+ }
+ else
+ {
+ if (nexthop->ifindex != newhop->ifindex ||
+ CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
+ SET_FLAG (rib->flags, ZEBRA_FLAG_CHANGED);
+ }
+ return 1;
+ }
}
else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL))
{
for (newhop = match->nexthop; newhop; newhop = newhop->next)
if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB)
- && ! CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_RECURSIVE))
+ && ! CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_RECURSIVE)
+ && nexthop_isactive (newhop))
{
if (set)
{
@@ -526,7 +608,27 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set,
|| newhop->type == NEXTHOP_TYPE_IPV6_IFINDEX
|| newhop->type == NEXTHOP_TYPE_IPV6_IFNAME)
nexthop->rifindex = newhop->ifindex;
+ if (nexthop->type == NEXTHOP_TYPE_IPV6)
+ nexthop->ifindex = newhop->ifindex;
+ }
+ else if (! CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)
+ || nexthop->rtype != newhop->type
+ || ((newhop->type == NEXTHOP_TYPE_IPV6
+ || newhop->type == NEXTHOP_TYPE_IPV6_IFINDEX
+ || newhop->type == NEXTHOP_TYPE_IPV6_IFNAME) &&
+ !IPV6_ADDR_SAME (&nexthop->rgate.ipv6,
+ &newhop->gate.ipv6))
+ || ((newhop->type == NEXTHOP_TYPE_IFINDEX
+ || newhop->type == NEXTHOP_TYPE_IFNAME
+ || newhop->type == NEXTHOP_TYPE_IPV6_IFINDEX
+ || newhop->type == NEXTHOP_TYPE_IPV6_IFNAME) &&
+ nexthop->rifindex != newhop->ifindex)
+ || ((nexthop->type == NEXTHOP_TYPE_IPV6) &&
+ (nexthop->ifindex != newhop->ifindex)))
+ {
+ SET_FLAG (rib->flags, ZEBRA_FLAG_CHANGED);
}
+
return 1;
}
return 0;
@@ -700,24 +802,24 @@ rib_lookup_ipv4_route (struct prefix_ipv4 *p, union sockunion * qgate)
/* Ok, we have a cood candidate, let's check it's nexthop list... */
for (nexthop = match->nexthop; nexthop; nexthop = nexthop->next)
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
- {
- /* We are happy with either direct or recursive hexthop */
- if (nexthop->gate.ipv4.s_addr == qgate->sin.sin_addr.s_addr ||
- nexthop->rgate.ipv4.s_addr == qgate->sin.sin_addr.s_addr)
- return ZEBRA_RIB_FOUND_EXACT;
- else
{
- if (IS_ZEBRA_DEBUG_RIB)
- {
- char gate_buf[INET_ADDRSTRLEN], rgate_buf[INET_ADDRSTRLEN], qgate_buf[INET_ADDRSTRLEN];
- inet_ntop (AF_INET, &nexthop->gate.ipv4.s_addr, gate_buf, INET_ADDRSTRLEN);
- inet_ntop (AF_INET, &nexthop->rgate.ipv4.s_addr, rgate_buf, INET_ADDRSTRLEN);
- inet_ntop (AF_INET, &qgate->sin.sin_addr.s_addr, qgate_buf, INET_ADDRSTRLEN);
- zlog_debug ("%s: qgate == %s, gate == %s, rgate == %s", __func__, qgate_buf, gate_buf, rgate_buf);
- }
- return ZEBRA_RIB_FOUND_NOGATE;
+ /* We are happy with either direct or recursive hexthop */
+ if (nexthop->gate.ipv4.s_addr == qgate->sin.sin_addr.s_addr ||
+ nexthop->rgate.ipv4.s_addr == qgate->sin.sin_addr.s_addr)
+ return ZEBRA_RIB_FOUND_EXACT;
+ else
+ {
+ if (IS_ZEBRA_DEBUG_RIB)
+ {
+ char gate_buf[INET_ADDRSTRLEN], rgate_buf[INET_ADDRSTRLEN], qgate_buf[INET_ADDRSTRLEN];
+ inet_ntop (AF_INET, &nexthop->gate.ipv4.s_addr, gate_buf, INET_ADDRSTRLEN);
+ inet_ntop (AF_INET, &nexthop->rgate.ipv4.s_addr, rgate_buf, INET_ADDRSTRLEN);
+ inet_ntop (AF_INET, &qgate->sin.sin_addr.s_addr, qgate_buf, INET_ADDRSTRLEN);
+ zlog_debug ("%s: qgate == %s, gate == %s, rgate == %s", __func__, qgate_buf, gate_buf, rgate_buf);
+ }
+ return ZEBRA_RIB_FOUND_NOGATE;
+ }
}
- }
return ZEBRA_RIB_NOTFOUND;
}
@@ -786,9 +888,18 @@ rib_match_ipv6 (struct in6_addr *addr)
}
#endif /* HAVE_IPV6 */
-#define RIB_SYSTEM_ROUTE(R) \
+#define RIB_SYSTEM_ROUTE(R) \
((R)->type == ZEBRA_ROUTE_KERNEL || (R)->type == ZEBRA_ROUTE_CONNECT)
+static inline int rib_is_managed(const struct rib *rib)
+{
+ switch (rib->type) {
+ case ZEBRA_ROUTE_KERNEL: return 0;
+ case ZEBRA_ROUTE_CONNECT: return set_interface_mode;
+ default: return 1;
+ }
+}
+
/* This function verifies reachability of one given nexthop, which can be
* numbered or unnumbered, IPv4 or IPv6. The result is unconditionally stored
* in nexthop->flags field. If the 4th parameter, 'set', is non-zero,
@@ -798,7 +909,6 @@ rib_match_ipv6 (struct in6_addr *addr)
*
* The return value is the final value of 'ACTIVE' flag.
*/
-
static int
nexthop_active_check (struct route_node *rn, struct rib *rib,
struct nexthop *nexthop, int set)
@@ -971,8 +1081,6 @@ rib_uninstall_kernel (struct route_node *rn, struct rib *rib)
break;
#ifdef HAVE_IPV6
case AF_INET6:
- if (IS_ZEBRA_DEBUG_RIB)
- zlog_debug ("%s: calling kernel_delete_ipv4 (%p, %p)", __func__, rn, rib);
ret = kernel_delete_ipv6 (&rn->p, rib);
break;
#endif /* HAVE_IPV6 */
@@ -991,7 +1099,7 @@ rib_uninstall (struct route_node *rn, struct rib *rib)
if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
{
redistribute_delete (&rn->p, rib);
- if (! RIB_SYSTEM_ROUTE (rib))
+ if (rib_is_managed (rib))
rib_uninstall_kernel (rn, rib);
UNSET_FLAG (rib->flags, ZEBRA_FLAG_SELECTED);
}
@@ -1111,22 +1219,23 @@ rib_process (struct route_node *rn)
if (select && select == fib)
{
if (IS_ZEBRA_DEBUG_RIB)
- zlog_debug ("%s: %s/%d: Updating existing route, select %p, fib %p",
- __func__, buf, rn->p.prefixlen, select, fib);
+ zlog_debug ("%s: %s/%d: Updating existing route, fib %p flags %#x status %#x",
+ __func__, buf, rn->p.prefixlen, fib,
+ (unsigned) select->flags, (unsigned) select->status);
if (CHECK_FLAG (select->flags, ZEBRA_FLAG_CHANGED))
{
redistribute_delete (&rn->p, select);
- if (! RIB_SYSTEM_ROUTE (select))
+ if (rib_is_managed (select))
rib_uninstall_kernel (rn, select);
/* Set real nexthop. */
nexthop_active_update (rn, select, 1);
- if (! RIB_SYSTEM_ROUTE (select))
+ if (rib_is_managed (select))
rib_install_kernel (rn, select);
redistribute_add (&rn->p, select);
}
- else if (! RIB_SYSTEM_ROUTE (select))
+ else if (rib_is_managed (select))
{
/* Housekeeping code to deal with
race conditions in kernel with linux
@@ -1157,7 +1266,7 @@ rib_process (struct route_node *rn)
zlog_debug ("%s: %s/%d: Removing existing route, fib %p", __func__,
buf, rn->p.prefixlen, fib);
redistribute_delete (&rn->p, fib);
- if (! RIB_SYSTEM_ROUTE (fib))
+ if (rib_is_managed (fib))
rib_uninstall_kernel (rn, fib);
UNSET_FLAG (fib->flags, ZEBRA_FLAG_SELECTED);
@@ -1177,7 +1286,7 @@ rib_process (struct route_node *rn)
/* Set real nexthop. */
nexthop_active_update (rn, select, 1);
- if (! RIB_SYSTEM_ROUTE (select))
+ if (rib_is_managed (select))
rib_install_kernel (rn, select);
SET_FLAG (select->flags, ZEBRA_FLAG_SELECTED);
redistribute_add (&rn->p, select);
@@ -1197,21 +1306,26 @@ end:
zlog_debug ("%s: %s/%d: rn %p dequeued", __func__, buf, rn->p.prefixlen, rn);
}
-/* Take a list of route_node structs and return 1, if there was a record picked from
- * it and processed by rib_process(). Don't process more, than one RN record; operate
- * only in the specified sub-queue.
+
+/* Take a list of route_node structs and return 1, if there was a record
+ * picked from it and processed by rib_process(). Don't process more,
+ * than one RN record; operate only in the specified sub-queue.
*/
static unsigned int
process_subq (struct list * subq, u_char qindex)
{
- struct listnode *lnode;
+ struct listnode *lnode = listhead (subq);
struct route_node *rnode;
- if (!(lnode = listhead (subq)))
+
+ if (!lnode)
return 0;
+
rnode = listgetdata (lnode);
rib_process (rnode);
+
if (rnode->info) /* The first RIB record is holding the flags bitmask. */
UNSET_FLAG (((struct rib *)rnode->info)->rn_status, RIB_ROUTE_QUEUED(qindex));
+
route_unlock_node (rnode);
list_delete_node (subq, lnode);
return 1;
@@ -1225,66 +1339,66 @@ static wq_item_status
meta_queue_process (struct work_queue *dummy, void *data)
{
struct meta_queue * mq = data;
- u_char i;
+ unsigned i;
+
for (i = 0; i < MQ_SIZE; i++)
if (process_subq (mq->subq[i], i))
- {
- mq->size--;
- break;
- }
+ {
+ mq->size--;
+ break;
+ }
return mq->size ? WQ_REQUEUE : WQ_SUCCESS;
}
-/* Look into the RN and queue it into one or more priority queues, increasing the size
- * for each data push done.
+/* Map from rib types to queue type (priority) in meta queue */
+static const u_char meta_queue_map[ZEBRA_ROUTE_MAX] = {
+ [ZEBRA_ROUTE_SYSTEM] = 4,
+ [ZEBRA_ROUTE_KERNEL] = 0,
+ [ZEBRA_ROUTE_CONNECT] = 0,
+ [ZEBRA_ROUTE_STATIC] = 1,
+ [ZEBRA_ROUTE_RIP] = 2,
+ [ZEBRA_ROUTE_RIPNG] = 2,
+ [ZEBRA_ROUTE_OSPF] = 2,
+ [ZEBRA_ROUTE_OSPF6] = 2,
+ [ZEBRA_ROUTE_ISIS] = 2,
+ [ZEBRA_ROUTE_BGP] = 3,
+ [ZEBRA_ROUTE_HSLS] = 4,
+};
+
+/* Look into the RN and queue it into one or more priority queues,
+ * increasing the size for each data push done.
*/
static void
rib_meta_queue_add (struct meta_queue *mq, struct route_node *rn)
{
- u_char qindex;
struct rib *rib;
char buf[INET6_ADDRSTRLEN];
+
if (IS_ZEBRA_DEBUG_RIB_Q)
inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN);
+
for (rib = rn->info; rib; rib = rib->next)
- {
- switch (rib->type)
- {
- case ZEBRA_ROUTE_KERNEL:
- case ZEBRA_ROUTE_CONNECT:
- qindex = 0;
- break;
- case ZEBRA_ROUTE_STATIC:
- qindex = 1;
- break;
- case ZEBRA_ROUTE_RIP:
- case ZEBRA_ROUTE_RIPNG:
- case ZEBRA_ROUTE_OSPF:
- case ZEBRA_ROUTE_OSPF6:
- case ZEBRA_ROUTE_ISIS:
- qindex = 2;
- break;
- case ZEBRA_ROUTE_BGP:
- qindex = 3;
- break;
- default:
- qindex = 4;
- break;
- }
- /* Invariant: at this point we always have rn->info set. */
- if (CHECK_FLAG (((struct rib *)rn->info)->rn_status, RIB_ROUTE_QUEUED(qindex)))
{
+ u_char qindex = meta_queue_map[rib->type];
+
+ /* Invariant: at this point we always have rn->info set. */
+ if (CHECK_FLAG (((struct rib *)rn->info)->rn_status, RIB_ROUTE_QUEUED(qindex)))
+ {
+ if (IS_ZEBRA_DEBUG_RIB_Q)
+ zlog_debug ("%s: %s/%d: rn %p is already queued in sub-queue %u",
+ __func__, buf, rn->p.prefixlen, rn, qindex);
+ continue;
+ }
+
+ SET_FLAG (((struct rib *)rn->info)->rn_status, RIB_ROUTE_QUEUED(qindex));
+ listnode_add (mq->subq[qindex], rn);
+ route_lock_node (rn);
+ mq->size++;
+
if (IS_ZEBRA_DEBUG_RIB_Q)
- zlog_debug ("%s: %s/%d: rn %p is already queued in sub-queue %u", __func__, buf, rn->p.prefixlen, rn, qindex);
- continue;
- }
- SET_FLAG (((struct rib *)rn->info)->rn_status, RIB_ROUTE_QUEUED(qindex));
- listnode_add (mq->subq[qindex], rn);
- route_lock_node (rn);
- mq->size++;
- if (IS_ZEBRA_DEBUG_RIB_Q)
- zlog_debug ("%s: %s/%d: queued rn %p into sub-queue %u", __func__, buf, rn->p.prefixlen, rn, qindex);
- }
+ zlog_debug ("%s: %s/%d: queued rn %p into sub-queue %u",
+ __func__, buf, rn->p.prefixlen, rn, qindex);
+ }
}
/* Add route_node to work queue and schedule processing */
@@ -1336,27 +1450,24 @@ rib_queue_add (struct zebra_t *zebra, struct route_node *rn)
return;
}
-/* Create new meta queue. A destructor function doesn't seem to be necessary here. */
+/* Create new meta queue.
+ A destructor function doesn't seem to be necessary here.
+ */
static struct meta_queue *
meta_queue_new (void)
{
struct meta_queue *new;
- unsigned i, failed = 0;
+ unsigned i;
+
+ new = XCALLOC (MTYPE_WORK_QUEUE, sizeof (struct meta_queue));
+ assert(new);
- if ((new = XCALLOC (MTYPE_WORK_QUEUE, sizeof (struct meta_queue))) == NULL)
- return NULL;
for (i = 0; i < MQ_SIZE; i++)
- if ((new->subq[i] = list_new ()) == NULL)
- failed = 1;
- if (failed)
- {
- for (i = 0; i < MQ_SIZE; i++)
- if (new->subq[i])
- list_delete (new->subq[i]);
- XFREE (MTYPE_WORK_QUEUE, new);
- return NULL;
- }
- new->size = 0;
+ {
+ new->subq[i] = list_new ();
+ assert(new->subq[i]);
+ }
+
return new;
}
@@ -1542,7 +1653,8 @@ int
rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p,
struct in_addr *gate, struct in_addr *src,
unsigned int ifindex, u_int32_t vrf_id,
- u_int32_t metric, u_char distance)
+ u_int32_t metric, u_int8_t distance,
+ u_int8_t scope, u_int8_t proto)
{
struct rib *rib;
struct rib *same = NULL;
@@ -1550,6 +1662,7 @@ rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p,
struct route_node *rn;
struct nexthop *nexthop;
+
/* Lookup table. */
table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
if (! table)
@@ -1598,6 +1711,7 @@ rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p,
/* Allocate new rib structure. */
rib = XCALLOC (MTYPE_RIB, sizeof (struct rib));
+
rib->type = type;
rib->distance = distance;
rib->flags = flags;
@@ -1605,6 +1719,8 @@ rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p,
rib->table = vrf_id;
rib->nexthop_num = 0;
rib->uptime = time (NULL);
+ rib->scope = scope;
+ rib->protocol = proto;
/* Nexthop settings. */
if (gate)
@@ -1615,12 +1731,12 @@ rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p,
nexthop_ipv4_add (rib, gate, src);
}
else
- nexthop_ifindex_add (rib, ifindex);
+ nexthop_ifindex_add (rib, ifindex, src);
/* If this route is kernel route, set FIB flag to the route. */
if (type == ZEBRA_ROUTE_KERNEL || type == ZEBRA_ROUTE_CONNECT)
for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
- SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+ SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
/* Link new rib to node.*/
if (IS_ZEBRA_DEBUG_RIB)
@@ -1653,10 +1769,10 @@ void rib_dump (const char * func, const struct prefix_ipv4 * p, const struct rib
zlog_debug ("%s: dumping RIB entry %p for %s/%d", func, rib, straddr1, p->prefixlen);
zlog_debug
(
- "%s: refcnt == %lu, uptime == %u, type == %u, table == %d",
+ "%s: refcnt == %lu, uptime == %lu, type == %u, table == %d",
func,
rib->refcnt,
- rib->uptime,
+ (unsigned long) rib->uptime,
rib->type,
rib->table
);
@@ -1778,8 +1894,7 @@ void rib_lookup_and_pushup (struct prefix_ipv4 * p)
*/
for (rib = rn->info; rib; rib = rib->next)
{
- if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED) &&
- ! RIB_SYSTEM_ROUTE (rib))
+ if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED) && rib_is_managed (rib))
{
changed = 1;
if (IS_ZEBRA_DEBUG_RIB)
@@ -1878,8 +1993,8 @@ rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p,
struct rib *fib = NULL;
struct rib *same = NULL;
struct nexthop *nexthop;
- char buf1[BUFSIZ];
- char buf2[BUFSIZ];
+ char buf1[INET_ADDRSTRLEN];
+ char buf2[INET_ADDRSTRLEN];
/* Lookup table. */
table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
@@ -1891,11 +2006,18 @@ rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p,
if (IS_ZEBRA_DEBUG_KERNEL && gate)
zlog_debug ("rib_delete_ipv4(): route delete %s/%d via %s ifindex %d",
- inet_ntop (AF_INET, &p->prefix, buf1, BUFSIZ),
+ inet_ntop (AF_INET, &p->prefix, buf1, INET_ADDRSTRLEN),
p->prefixlen,
inet_ntoa (*gate),
ifindex);
+ if (IS_ZEBRA_DEBUG_KERNEL && !gate)
+ zlog_debug ("rib_delete_ipv4(): route delete %s/%d directly, %s ifindex %d",
+ inet_ntop (AF_INET, &p->prefix, buf1, BUFSIZ),
+ p->prefixlen,
+ ifindex2ifname(ifindex),
+ ifindex);
+
/* Lookup route node. */
rn = route_node_lookup (table, (struct prefix *) p);
if (! rn)
@@ -1904,13 +2026,13 @@ rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p,
{
if (gate)
zlog_debug ("route %s/%d via %s ifindex %d doesn't exist in rib",
- inet_ntop (AF_INET, &p->prefix, buf1, BUFSIZ),
+ inet_ntop (AF_INET, &p->prefix, buf1, INET_ADDRSTRLEN),
p->prefixlen,
- inet_ntop (AF_INET, gate, buf2, BUFSIZ),
+ inet_ntop (AF_INET, gate, buf2, INET_ADDRSTRLEN),
ifindex);
else
zlog_debug ("route %s/%d ifindex %d doesn't exist in rib",
- inet_ntop (AF_INET, &p->prefix, buf1, BUFSIZ),
+ inet_ntop (AF_INET, &p->prefix, buf1, INET_ADDRSTRLEN),
p->prefixlen,
ifindex);
}
@@ -1942,7 +2064,7 @@ rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p,
break;
}
/* Make sure that the route found has the same gateway. */
- else if (gate == NULL ||
+ else if (gate != NULL &&
((nexthop = rib->nexthop) &&
(IPV4_ADDR_SAME (&nexthop->gate.ipv4, gate) ||
IPV4_ADDR_SAME (&nexthop->rgate.ipv4, gate))))
@@ -1970,14 +2092,14 @@ rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p,
{
if (gate)
zlog_debug ("route %s/%d via %s ifindex %d type %d doesn't exist in rib",
- inet_ntop (AF_INET, &p->prefix, buf1, BUFSIZ),
+ inet_ntop (AF_INET, &p->prefix, buf1, INET_ADDRSTRLEN),
p->prefixlen,
- inet_ntop (AF_INET, gate, buf2, BUFSIZ),
+ inet_ntop (AF_INET, gate, buf2, INET_ADDRSTRLEN),
ifindex,
type);
else
zlog_debug ("route %s/%d ifindex %d type %d doesn't exist in rib",
- inet_ntop (AF_INET, &p->prefix, buf1, BUFSIZ),
+ inet_ntop (AF_INET, &p->prefix, buf1, INET_ADDRSTRLEN),
p->prefixlen,
ifindex,
type);
@@ -2197,8 +2319,7 @@ static_add_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname,
static_delete_ipv4 (p, gate, ifname, update->distance, vrf_id);
/* Make new static route structure. */
- si = XMALLOC (MTYPE_STATIC_IPV4, sizeof (struct static_ipv4));
- memset (si, 0, sizeof (struct static_ipv4));
+ si = XCALLOC (MTYPE_STATIC_IPV4, sizeof (struct static_ipv4));
si->type = type;
si->distance = distance;
@@ -2239,6 +2360,9 @@ static_add_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname,
/* Install into rib. */
static_install_ipv4 (p, si);
+ /* Scan for possible recursive route changes */
+ rib_update();
+
return 1;
}
@@ -2303,6 +2427,9 @@ static_delete_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname,
route_unlock_node (rn);
+ /* Scan for possible recursive route changes */
+ rib_update();
+
return 1;
}
@@ -2323,7 +2450,7 @@ rib_bogus_ipv6 (int type, struct prefix_ipv6 *p,
if (type == ZEBRA_ROUTE_KERNEL && IN6_IS_ADDR_UNSPECIFIED (&p->prefix)
&& p->prefixlen == 96 && gate && IN6_IS_ADDR_UNSPECIFIED (gate))
{
- kernel_delete_ipv6_old (p, gate, ifindex, 0, table);
+ kernel_delete_ipv6_old (p, gate, ifindex, table);
return 1;
}
return 0;
@@ -2405,7 +2532,7 @@ rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p,
nexthop_ipv6_add (rib, gate);
}
else
- nexthop_ifindex_add (rib, ifindex);
+ nexthop_ifindex_add (rib, ifindex, NULL);
/* If this route is kernel route, set FIB flag to the route. */
if (type == ZEBRA_ROUTE_KERNEL || type == ZEBRA_ROUTE_CONNECT)
@@ -2434,8 +2561,8 @@ rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p,
struct rib *fib = NULL;
struct rib *same = NULL;
struct nexthop *nexthop;
- char buf1[BUFSIZ];
- char buf2[BUFSIZ];
+ char buf1[INET6_ADDRSTRLEN];
+ char buf2[INET6_ADDRSTRLEN];
/* Apply mask. */
apply_mask_ipv6 (p);
@@ -2453,13 +2580,13 @@ rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p,
{
if (gate)
zlog_debug ("route %s/%d via %s ifindex %d doesn't exist in rib",
- inet_ntop (AF_INET6, &p->prefix, buf1, BUFSIZ),
+ inet_ntop (AF_INET6, &p->prefix, buf1, INET6_ADDRSTRLEN),
p->prefixlen,
- inet_ntop (AF_INET6, gate, buf2, BUFSIZ),
+ inet_ntop (AF_INET6, gate, buf2, INET6_ADDRSTRLEN),
ifindex);
else
zlog_debug ("route %s/%d ifindex %d doesn't exist in rib",
- inet_ntop (AF_INET6, &p->prefix, buf1, BUFSIZ),
+ inet_ntop (AF_INET6, &p->prefix, buf1, INET6_ADDRSTRLEN),
p->prefixlen,
ifindex);
}
@@ -2519,14 +2646,14 @@ rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p,
{
if (gate)
zlog_debug ("route %s/%d via %s ifindex %d type %d doesn't exist in rib",
- inet_ntop (AF_INET6, &p->prefix, buf1, BUFSIZ),
+ inet_ntop (AF_INET6, &p->prefix, buf1, INET6_ADDRSTRLEN),
p->prefixlen,
- inet_ntop (AF_INET6, gate, buf2, BUFSIZ),
+ inet_ntop (AF_INET6, gate, buf2, INET6_ADDRSTRLEN),
ifindex,
type);
else
zlog_debug ("route %s/%d ifindex %d type %d doesn't exist in rib",
- inet_ntop (AF_INET6, &p->prefix, buf1, BUFSIZ),
+ inet_ntop (AF_INET6, &p->prefix, buf1, INET6_ADDRSTRLEN),
p->prefixlen,
ifindex,
type);
@@ -2741,8 +2868,7 @@ static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate,
}
/* Make new static route structure. */
- si = XMALLOC (MTYPE_STATIC_IPV6, sizeof (struct static_ipv6));
- memset (si, 0, sizeof (struct static_ipv6));
+ si = XCALLOC (MTYPE_STATIC_IPV6, sizeof (struct static_ipv6));
si->type = type;
si->distance = distance;
@@ -2785,6 +2911,8 @@ static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate,
/* Install into rib. */
static_install_ipv6 (p, si);
+ /* Scan for possible recursive route changes */
+ rib_update();
return 1;
}
@@ -2838,6 +2966,7 @@ static_delete_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate,
XFREE (0, si->ifname);
XFREE (MTYPE_STATIC_IPV6, si);
+ rib_update();
return 1;
}
#endif /* HAVE_IPV6 */
@@ -2862,6 +2991,7 @@ rib_update (void)
rib_queue_add (&zebrad, rn);
}
+#if 0
/* Interface goes up. */
static void
rib_if_up (struct interface *ifp)
@@ -2875,6 +3005,7 @@ rib_if_down (struct interface *ifp)
{
rib_update ();
}
+#endif
/* Remove all routes which comes from non main table. */
static void
@@ -2942,6 +3073,66 @@ rib_sweep_route (void)
rib_sweep_table (vrf_table (AFI_IP, SAFI_UNICAST, 0));
rib_sweep_table (vrf_table (AFI_IP6, SAFI_UNICAST, 0));
}
+
+/* When all IPV4 subnets are gone on Linux, the kernel frees all routes */
+void
+rib_flush_interface(afi_t afi, struct interface *ifp)
+{
+ struct route_table *table;
+ struct route_node *rn;
+ struct rib *rib, *next;
+
+ table = vrf_table(afi, SAFI_UNICAST, 0);
+ if (!table)
+ return;
+
+ if (IS_ZEBRA_DEBUG_RIB)
+ zlog_debug ("%s: flushing references to %s", __func__, ifp->name);
+
+ for (rn = route_top (table); rn; rn = route_next (rn))
+ for (rib = rn->info; rib; rib = next)
+ {
+ struct nexthop *nexthop;
+
+ next = rib->next;
+
+ if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED))
+ continue;
+
+ switch(rib->type) {
+ case ZEBRA_ROUTE_KERNEL:
+ if ( (nexthop = rib->nexthop) &&
+ (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX ||
+ nexthop->type == NEXTHOP_TYPE_IFINDEX) &&
+ nexthop->ifindex == ifp->ifindex)
+ {
+ if (IS_ZEBRA_DEBUG_RIB)
+ zlog_debug ("%s: calling rib_delnode (%p, %p) on kernel RIB entry",
+ __func__, rn, rib);
+ rib_delnode(rn, rib);
+ }
+ break;
+
+ case ZEBRA_ROUTE_STATIC:
+ for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+ switch(nexthop->type) {
+ case NEXTHOP_TYPE_IPV4:
+ case NEXTHOP_TYPE_IPV6:
+ case NEXTHOP_TYPE_IFINDEX:
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ if (nexthop->ifindex == ifp->ifindex)
+ UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+ break;
+ case NEXTHOP_TYPE_IFNAME:
+ case NEXTHOP_TYPE_IPV4_IFNAME:
+ case NEXTHOP_TYPE_IPV6_IFNAME:
+ if (strcmp(nexthop->ifname, ifp->name) == 0)
+ UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+ }
+ }
+ }
+}
/* Close RIB and clean up kernel routes. */
static void
@@ -2954,7 +3145,7 @@ rib_close_table (struct route_table *table)
for (rn = route_top (table); rn; rn = route_next (rn))
for (rib = rn->info; rib; rib = rib->next)
{
- if (! RIB_SYSTEM_ROUTE (rib)
+ if (rib_is_managed (rib)
&& CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
rib_uninstall_kernel (rn, rib);
}
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
index 0c313921..d4e3a4ae 100644
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -87,6 +87,9 @@ zebra_static_ipv4 (struct vty *vty, int add_cmd, const char *dest_str,
return CMD_SUCCESS;
}
+ /* Mark static routes as internal so they get evaluated as recursive */
+ SET_FLAG (flag, ZEBRA_FLAG_INTERNAL);
+
/* Route flags */
if (flag_str) {
switch(flag_str[0]) {
@@ -1057,29 +1060,65 @@ DEFUN (show_ip_route_prefix,
}
static void
-zebra_show_ip_route (struct vty *vty, struct vrf *vrf)
+vty_show_ip_route_summary (struct vty *vty, struct route_table *table)
{
- vty_out (vty, "IP routing table name is %s(%d)%s",
- vrf->name ? vrf->name : "", vrf->id, VTY_NEWLINE);
-
- vty_out (vty, "Route Source Networks%s", VTY_NEWLINE);
- vty_out (vty, "connected %d%s", 0, VTY_NEWLINE);
- vty_out (vty, "static %d%s", 0, VTY_NEWLINE);
- vty_out (vty, "rip %d%s", 0, VTY_NEWLINE);
-
- vty_out (vty, "bgp %d%s", 0, VTY_NEWLINE);
- vty_out (vty, " External: %d Internal: %d Local: %d%s",
- 0, 0, 0, VTY_NEWLINE);
-
- vty_out (vty, "ospf %d%s", 0, VTY_NEWLINE);
- vty_out (vty,
- " Intra-area: %d Inter-area: %d External-1: %d External-2: %d%s",
- 0, 0, 0, 0, VTY_NEWLINE);
- vty_out (vty, " NSSA External-1: %d NSSA External-2: %d%s",
- 0, 0, VTY_NEWLINE);
-
- vty_out (vty, "internal %d%s", 0, VTY_NEWLINE);
- vty_out (vty, "Total %d%s", 0, VTY_NEWLINE);
+ struct route_node *rn;
+ struct rib *rib;
+ struct nexthop *nexthop;
+#define ZEBRA_ROUTE_IBGP ZEBRA_ROUTE_MAX
+#define ZEBRA_ROUTE_TOTAL (ZEBRA_ROUTE_IBGP + 1)
+ u_int32_t rib_cnt[ZEBRA_ROUTE_TOTAL + 1];
+ u_int32_t fib_cnt[ZEBRA_ROUTE_TOTAL + 1];
+ u_int32_t i;
+
+ memset (&rib_cnt, 0, sizeof(rib_cnt));
+ memset (&fib_cnt, 0, sizeof(fib_cnt));
+ for (rn = route_top (table); rn; rn = route_next (rn))
+ for (rib = rn->info; rib; rib = rib->next)
+ for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+ {
+ rib_cnt[ZEBRA_ROUTE_TOTAL]++;
+ rib_cnt[rib->type]++;
+ if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
+ {
+ fib_cnt[ZEBRA_ROUTE_TOTAL]++;
+ fib_cnt[rib->type]++;
+ }
+ if (rib->type == ZEBRA_ROUTE_BGP &&
+ CHECK_FLAG (rib->flags, ZEBRA_FLAG_IBGP))
+ {
+ rib_cnt[ZEBRA_ROUTE_IBGP]++;
+ if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
+ fib_cnt[ZEBRA_ROUTE_IBGP]++;
+ }
+ }
+
+ vty_out (vty, "%-20s %-20s %-20s %s",
+ "Route Source", "Routes", "FIB", VTY_NEWLINE);
+
+ for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+ {
+ if (rib_cnt[i] > 0)
+ {
+ if (i == ZEBRA_ROUTE_BGP)
+ {
+ vty_out (vty, "%-20s %-20d %-20d %s", "ebgp",
+ rib_cnt[ZEBRA_ROUTE_BGP] - rib_cnt[ZEBRA_ROUTE_IBGP],
+ fib_cnt[ZEBRA_ROUTE_BGP] - fib_cnt[ZEBRA_ROUTE_IBGP],
+ VTY_NEWLINE);
+ vty_out (vty, "%-20s %-20d %-20d %s", "ibgp",
+ rib_cnt[ZEBRA_ROUTE_IBGP], fib_cnt[ZEBRA_ROUTE_IBGP],
+ VTY_NEWLINE);
+ }
+ else
+ vty_out (vty, "%-20s %-20d %-20d %s", zebra_route_string(i),
+ rib_cnt[i], fib_cnt[i], VTY_NEWLINE);
+ }
+ }
+
+ vty_out (vty, "------%s", VTY_NEWLINE);
+ vty_out (vty, "%-20s %-20d %-20d %s", "Totals", rib_cnt[ZEBRA_ROUTE_TOTAL],
+ fib_cnt[ZEBRA_ROUTE_TOTAL], VTY_NEWLINE);
}
/* Show route summary. */
@@ -1091,17 +1130,13 @@ DEFUN (show_ip_route_summary,
"IP routing table\n"
"Summary of all routes\n")
{
- struct vrf *vrf;
+ struct route_table *table;
- /* Default table id is zero. */
- vrf = vrf_lookup (0);
- if (! vrf)
- {
- vty_out (vty, "%% No Default-IP-Routing-Table%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
+ table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
+ if (! table)
+ return CMD_SUCCESS;
- zebra_show_ip_route (vty, vrf);
+ vty_show_ip_route_summary (vty, table);
return CMD_SUCCESS;
}
@@ -1943,6 +1978,26 @@ DEFUN (show_ipv6_route_prefix,
return CMD_SUCCESS;
}
+/* Show route summary. */
+DEFUN (show_ipv6_route_summary,
+ show_ipv6_route_summary_cmd,
+ "show ipv6 route summary",
+ SHOW_STR
+ IP_STR
+ "IPv6 routing table\n"
+ "Summary of all IPv6 routes\n")
+{
+ struct route_table *table;
+
+ table = vrf_table (AFI_IP6, SAFI_UNICAST, 0);
+ if (! table)
+ return CMD_SUCCESS;
+
+ vty_show_ip_route_summary (vty, table);
+
+ return CMD_SUCCESS;
+}
+
/* Write IPv6 static route configuration. */
static int
static_config_ipv6 (struct vty *vty)
@@ -2030,10 +2085,10 @@ static int config_write_protocol(struct vty *vty)
}
/* table node for protocol filtering */
-struct cmd_node protocol_node = { PROTOCOL_NODE, "", 1 };
+static struct cmd_node protocol_node = { PROTOCOL_NODE, "", 1 };
/* IP node for static routes. */
-struct cmd_node ip_node = { IP_NODE, "", 1 };
+static struct cmd_node ip_node = { IP_NODE, "", 1 };
/* Route VTY. */
void
@@ -2076,17 +2131,14 @@ zebra_vty_init (void)
install_element (VIEW_NODE, &show_ip_route_prefix_longer_cmd);
install_element (VIEW_NODE, &show_ip_route_protocol_cmd);
install_element (VIEW_NODE, &show_ip_route_supernets_cmd);
+ install_element (VIEW_NODE, &show_ip_route_summary_cmd);
install_element (ENABLE_NODE, &show_ip_route_cmd);
install_element (ENABLE_NODE, &show_ip_route_addr_cmd);
install_element (ENABLE_NODE, &show_ip_route_prefix_cmd);
install_element (ENABLE_NODE, &show_ip_route_prefix_longer_cmd);
install_element (ENABLE_NODE, &show_ip_route_protocol_cmd);
install_element (ENABLE_NODE, &show_ip_route_supernets_cmd);
-
-#if 0
- install_element (VIEW_NODE, &show_ip_route_summary_cmd);
install_element (ENABLE_NODE, &show_ip_route_summary_cmd);
-#endif /* 0 */
#ifdef HAVE_IPV6
install_element (CONFIG_NODE, &ipv6_route_cmd);
@@ -2106,6 +2158,7 @@ zebra_vty_init (void)
install_element (CONFIG_NODE, &no_ipv6_route_ifname_pref_cmd);
install_element (CONFIG_NODE, &no_ipv6_route_ifname_flags_pref_cmd);
install_element (VIEW_NODE, &show_ipv6_route_cmd);
+ install_element (VIEW_NODE, &show_ipv6_route_summary_cmd);
install_element (VIEW_NODE, &show_ipv6_route_protocol_cmd);
install_element (VIEW_NODE, &show_ipv6_route_addr_cmd);
install_element (VIEW_NODE, &show_ipv6_route_prefix_cmd);
@@ -2115,5 +2168,6 @@ zebra_vty_init (void)
install_element (ENABLE_NODE, &show_ipv6_route_addr_cmd);
install_element (ENABLE_NODE, &show_ipv6_route_prefix_cmd);
install_element (ENABLE_NODE, &show_ipv6_route_prefix_longer_cmd);
+ install_element (ENABLE_NODE, &show_ipv6_route_summary_cmd);
#endif /* HAVE_IPV6 */
}
diff --git a/zebra/zserv.c b/zebra/zserv.c
index ef79eaad..76e74088 100644
--- a/zebra/zserv.c
+++ b/zebra/zserv.c
@@ -773,7 +773,7 @@ zread_ipv4_add (struct zserv *client, u_short length)
{
case ZEBRA_NEXTHOP_IFINDEX:
ifindex = stream_getl (s);
- nexthop_ifindex_add (rib, ifindex);
+ nexthop_ifindex_add (rib, ifindex, NULL);
break;
case ZEBRA_NEXTHOP_IFNAME:
ifname_len = stream_getc (s);
@@ -1569,7 +1569,7 @@ config_write_table (struct vty *vty)
}
/* table node for routing tables. */
-struct cmd_node table_node =
+static struct cmd_node table_node =
{
TABLE_NODE,
"", /* This node has no interface. */
@@ -1689,7 +1689,7 @@ config_write_forwarding (struct vty *vty)
}
/* table node for routing tables. */
-struct cmd_node forwarding_node =
+static struct cmd_node forwarding_node =
{
FORWARDING_NODE,
"", /* This node has no interface. */
diff --git a/zebra/zserv.h b/zebra/zserv.h
index 87a33a45..1171b619 100644
--- a/zebra/zserv.h
+++ b/zebra/zserv.h
@@ -76,7 +76,7 @@ struct zebra_t
struct list *client_list;
/* default table */
- int rtm_table_default;
+ u_int32_t rtm_table_default;
/* rib work queue */
struct work_queue *ribq;