summaryrefslogtreecommitdiff
path: root/zebra
diff options
context:
space:
mode:
Diffstat (limited to 'zebra')
-rw-r--r--zebra/rib.h4
-rw-r--r--zebra/rt_netlink.c188
-rw-r--r--zebra/zebra_rib.c2
3 files changed, 165 insertions, 29 deletions
diff --git a/zebra/rib.h b/zebra/rib.h
index 887ed3c2..b5c9e052 100644
--- a/zebra/rib.h
+++ b/zebra/rib.h
@@ -225,6 +225,10 @@ 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 *,
struct in_addr *);
+extern struct nexthop *nexthop_ipv4_ifindex_add (struct rib *,
+ struct in_addr *,
+ struct in_addr *,
+ unsigned int);
extern void rib_lookup_and_dump (struct prefix_ipv4 *);
extern void rib_lookup_and_pushup (struct prefix_ipv4 *);
extern void rib_dump (const char *, const struct prefix_ipv4 *, const struct rib *);
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index 7652f80a..2cde50a1 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -32,6 +32,7 @@
#include "prefix.h"
#include "connected.h"
#include "table.h"
+#include "memory.h"
#include "rib.h"
#include "thread.h"
#include "privs.h"
@@ -426,6 +427,37 @@ netlink_parse_rtattr (struct rtattr **tb, int max, struct rtattr *rta,
}
}
+/* Utility function to parse hardware link-layer address and update ifp */
+static void
+netlink_interface_update_hw_addr (struct rtattr **tb, struct interface *ifp)
+{
+ int i;
+
+ if (tb[IFLA_ADDRESS])
+ {
+ int hw_addr_len;
+
+ hw_addr_len = RTA_PAYLOAD (tb[IFLA_ADDRESS]);
+
+ if (hw_addr_len > INTERFACE_HWADDR_MAX)
+ zlog_warn ("Hardware address is too large: %d", hw_addr_len);
+ else
+ {
+ ifp->hw_addr_len = hw_addr_len;
+ memcpy (ifp->hw_addr, RTA_DATA (tb[IFLA_ADDRESS]), hw_addr_len);
+
+ for (i = 0; i < hw_addr_len; i++)
+ if (ifp->hw_addr[i] != 0)
+ break;
+
+ if (i == hw_addr_len)
+ ifp->hw_addr_len = 0;
+ else
+ ifp->hw_addr_len = hw_addr_len;
+ }
+ }
+}
+
/* Called from interface_lookup_netlink(). This function is only used
during bootstrap. */
static int
@@ -436,7 +468,6 @@ netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h)
struct rtattr *tb[IFLA_MAX + 1];
struct interface *ifp;
char *name;
- int i;
ifi = NLMSG_DATA (h);
@@ -474,30 +505,7 @@ netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h)
/* Hardware type and address. */
ifp->hw_type = ifi->ifi_type;
-
- if (tb[IFLA_ADDRESS])
- {
- int hw_addr_len;
-
- hw_addr_len = RTA_PAYLOAD (tb[IFLA_ADDRESS]);
-
- if (hw_addr_len > INTERFACE_HWADDR_MAX)
- zlog_warn ("Hardware address is too large: %d", hw_addr_len);
- else
- {
- ifp->hw_addr_len = hw_addr_len;
- memcpy (ifp->hw_addr, RTA_DATA (tb[IFLA_ADDRESS]), hw_addr_len);
-
- for (i = 0; i < hw_addr_len; i++)
- if (ifp->hw_addr[i] != 0)
- break;
-
- if (i == hw_addr_len)
- ifp->hw_addr_len = 0;
- else
- ifp->hw_addr_len = hw_addr_len;
- }
- }
+ netlink_interface_update_hw_addr (tb, ifp);
if_add_update (ifp);
@@ -709,7 +717,6 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h)
if (tb[RTA_PREFSRC])
src = RTA_DATA (tb[RTA_PREFSRC]);
- /* Multipath treatment is needed. */
if (tb[RTA_GATEWAY])
gate = RTA_DATA (tb[RTA_GATEWAY]);
@@ -723,7 +730,64 @@ 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);
+ if (!tb[RTA_MULTIPATH])
+ rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, src, index,
+ table, metric, 0);
+ else
+ {
+ /* This is a multipath route */
+
+ struct rib *rib;
+ struct rtnexthop *rtnh =
+ (struct rtnexthop *) RTA_DATA (tb[RTA_MULTIPATH]);
+
+ len = RTA_PAYLOAD (tb[RTA_MULTIPATH]);
+
+ rib = XCALLOC (MTYPE_RIB, sizeof (struct rib));
+ rib->type = ZEBRA_ROUTE_KERNEL;
+ rib->distance = 0;
+ rib->flags = flags;
+ rib->metric = metric;
+ rib->table = table;
+ rib->nexthop_num = 0;
+ rib->uptime = time (NULL);
+
+ for (;;)
+ {
+ if (len < (int) sizeof (*rtnh) || rtnh->rtnh_len > len)
+ break;
+
+ rib->nexthop_num++;
+ index = rtnh->rtnh_ifindex;
+ gate = 0;
+ if (rtnh->rtnh_len > sizeof (*rtnh))
+ {
+ memset (tb, 0, sizeof (tb));
+ netlink_parse_rtattr (tb, RTA_MAX, RTNH_DATA (rtnh),
+ rtnh->rtnh_len - sizeof (*rtnh));
+ if (tb[RTA_GATEWAY])
+ gate = RTA_DATA (tb[RTA_GATEWAY]);
+ }
+
+ if (gate)
+ {
+ if (index)
+ nexthop_ipv4_ifindex_add (rib, gate, src, index);
+ else
+ nexthop_ipv4_add (rib, gate, src);
+ }
+ else
+ nexthop_ifindex_add (rib, index);
+
+ len -= NLMSG_ALIGN(rtnh->rtnh_len);
+ rtnh = RTNH_NEXT(rtnh);
+ }
+
+ if (rib->nexthop_num == 0)
+ XFREE (MTYPE_RIB, rib);
+ else
+ rib_add_ipv4_multipath (&p, rib);
+ }
}
#ifdef HAVE_IPV6
if (rtm->rtm_family == AF_INET6)
@@ -768,6 +832,7 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
int index;
int table;
+ int metric;
void *dest;
void *gate;
void *src;
@@ -825,6 +890,7 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
}
index = 0;
+ metric = 0;
dest = NULL;
gate = NULL;
src = NULL;
@@ -843,6 +909,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 = *(int *) RTA_DATA(tb[RTA_PRIORITY]);
+
if (rtm->rtm_family == AF_INET)
{
struct prefix_ipv4 p;
@@ -861,7 +930,66 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
}
if (h->nlmsg_type == RTM_NEWROUTE)
- rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, table, 0, 0);
+ {
+ if (!tb[RTA_MULTIPATH])
+ rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, table,
+ metric, 0);
+ else
+ {
+ /* This is a multipath route */
+
+ struct rib *rib;
+ struct rtnexthop *rtnh =
+ (struct rtnexthop *) RTA_DATA (tb[RTA_MULTIPATH]);
+
+ len = RTA_PAYLOAD (tb[RTA_MULTIPATH]);
+
+ rib = XCALLOC (MTYPE_RIB, sizeof (struct rib));
+ rib->type = ZEBRA_ROUTE_KERNEL;
+ rib->distance = 0;
+ rib->flags = 0;
+ rib->metric = metric;
+ rib->table = table;
+ rib->nexthop_num = 0;
+ rib->uptime = time (NULL);
+
+ for (;;)
+ {
+ if (len < (int) sizeof (*rtnh) || rtnh->rtnh_len > len)
+ break;
+
+ rib->nexthop_num++;
+ index = rtnh->rtnh_ifindex;
+ gate = 0;
+ if (rtnh->rtnh_len > sizeof (*rtnh))
+ {
+ memset (tb, 0, sizeof (tb));
+ netlink_parse_rtattr (tb, RTA_MAX, RTNH_DATA (rtnh),
+ rtnh->rtnh_len - sizeof (*rtnh));
+ if (tb[RTA_GATEWAY])
+ gate = RTA_DATA (tb[RTA_GATEWAY]);
+ }
+
+ if (gate)
+ {
+ if (index)
+ nexthop_ipv4_ifindex_add (rib, gate, src, index);
+ else
+ nexthop_ipv4_add (rib, gate, src);
+ }
+ else
+ nexthop_ifindex_add (rib, index);
+
+ len -= NLMSG_ALIGN(rtnh->rtnh_len);
+ rtnh = RTNH_NEXT(rtnh);
+ }
+
+ if (rib->nexthop_num == 0)
+ XFREE (MTYPE_RIB, rib);
+ else
+ rib_add_ipv4_multipath (&p, rib);
+ }
+ }
else
rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table);
}
@@ -954,6 +1082,8 @@ netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
ifp->metric = 1;
+ netlink_interface_update_hw_addr (tb, ifp);
+
/* If new link is added. */
if_add_update (ifp);
}
@@ -964,6 +1094,8 @@ netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
ifp->metric = 1;
+ netlink_interface_update_hw_addr (tb, ifp);
+
if (if_is_operative (ifp))
{
ifp->flags = ifi->ifi_flags & 0x0000fffff;
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index 12f3fa5a..580b75bb 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -225,7 +225,7 @@ nexthop_ipv4_add (struct rib *rib, struct in_addr *ipv4, struct in_addr *src)
return nexthop;
}
-static struct nexthop *
+struct nexthop *
nexthop_ipv4_ifindex_add (struct rib *rib, struct in_addr *ipv4,
struct in_addr *src, unsigned int ifindex)
{