summaryrefslogtreecommitdiff
path: root/zebra/rt_netlink.c
diff options
context:
space:
mode:
Diffstat (limited to 'zebra/rt_netlink.c')
-rw-r--r--zebra/rt_netlink.c85
1 files changed, 48 insertions, 37 deletions
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index 573f60f4ca..0cc2e0217f 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -267,7 +267,7 @@ static int netlink_route_change_read_unicast(struct sockaddr_nl *snl,
struct rtattr *tb[RTA_MAX + 1];
u_char flags = 0;
struct prefix p;
- struct prefix_ipv6 src_p;
+ struct prefix_ipv6 src_p = {};
vrf_id_t vrf_id = VRF_DEFAULT;
char anyaddr[16] = {0};
@@ -277,6 +277,7 @@ static int netlink_route_change_read_unicast(struct sockaddr_nl *snl,
int table;
int metric = 0;
u_int32_t mtu = 0;
+ uint8_t distance = 0;
void *dest = NULL;
void *gate = NULL;
@@ -405,16 +406,38 @@ static int netlink_route_change_read_unicast(struct sockaddr_nl *snl,
return 0;
}
+ /*
+ * For ZEBRA_ROUTE_KERNEL types:
+ *
+ * The metric/priority of the route received from the kernel
+ * is a 32 bit number. We are going to interpret the high
+ * order byte as the Admin Distance and the low order 3 bytes
+ * as the metric.
+ *
+ * This will allow us to do two things:
+ * 1) Allow the creation of kernel routes that can be
+ * overridden by zebra.
+ * 2) Allow the old behavior for 'most' kernel route types
+ * if a user enters 'ip route ...' v4 routes get a metric
+ * of 0 and v6 routes get a metric of 1024. Both of these
+ * values will end up with a admin distance of 0, which
+ * will cause them to win for the purposes of zebra.
+ */
+ if (proto == ZEBRA_ROUTE_KERNEL) {
+ distance = (metric >> 24) & 0xFF;
+ metric = (metric & 0x00FFFFFF);
+ }
+
if (IS_ZEBRA_DEBUG_KERNEL) {
char buf[PREFIX_STRLEN];
char buf2[PREFIX_STRLEN];
zlog_debug(
- "%s %s%s%s vrf %u", nl_msg_type_to_str(h->nlmsg_type),
+ "%s %s%s%s vrf %u metric: %d Admin Distance: %d", nl_msg_type_to_str(h->nlmsg_type),
prefix2str(&p, buf, sizeof(buf)),
src_p.prefixlen ? " from " : "",
src_p.prefixlen ? prefix2str(&src_p, buf2, sizeof(buf2))
: "",
- vrf_id);
+ vrf_id, metric, distance);
}
afi_t afi = AFI_IP;
@@ -454,7 +477,7 @@ static int netlink_route_change_read_unicast(struct sockaddr_nl *snl,
memcpy(&nh.gate, gate, sz);
rib_add(afi, SAFI_UNICAST, vrf_id, proto,
- 0, flags, &p, NULL, &nh, table, metric, mtu, 0);
+ 0, flags, &p, NULL, &nh, table, metric, mtu, distance);
} else {
/* This is a multipath route */
@@ -466,7 +489,7 @@ static int netlink_route_change_read_unicast(struct sockaddr_nl *snl,
re = XCALLOC(MTYPE_RE, sizeof(struct route_entry));
re->type = proto;
- re->distance = 0;
+ re->distance = distance;
re->flags = flags;
re->metric = metric;
re->mtu = mtu;
@@ -822,7 +845,7 @@ static void _netlink_route_build_singlepath(const char *routedesc, int bytelen,
{
struct nexthop_label *nh_label;
mpls_lse_t out_lse[MPLS_MAX_LABELS];
- char label_buf[100];
+ char label_buf[256];
/*
* label_buf is *only* currently used within debugging.
@@ -853,12 +876,13 @@ static void _netlink_route_build_singlepath(const char *routedesc, int bytelen,
0, 0, bos);
if (IS_ZEBRA_DEBUG_KERNEL) {
if (!num_labels)
- sprintf(label_buf, "label %d",
+ sprintf(label_buf, "label %u",
nh_label->label[i]);
else {
- sprintf(label_buf1, "/%d",
+ sprintf(label_buf1, "/%u",
nh_label->label[i]);
- strcat(label_buf, label_buf1);
+ strlcat(label_buf, label_buf1,
+ sizeof(label_buf));
}
}
num_labels++;
@@ -1021,7 +1045,7 @@ static void _netlink_route_build_multipath(const char *routedesc, int bytelen,
{
struct nexthop_label *nh_label;
mpls_lse_t out_lse[MPLS_MAX_LABELS];
- char label_buf[100];
+ char label_buf[256];
rtnh->rtnh_len = sizeof(*rtnh);
rtnh->rtnh_flags = 0;
@@ -1057,12 +1081,13 @@ static void _netlink_route_build_multipath(const char *routedesc, int bytelen,
0, 0, bos);
if (IS_ZEBRA_DEBUG_KERNEL) {
if (!num_labels)
- sprintf(label_buf, "label %d",
+ sprintf(label_buf, "label %u",
nh_label->label[i]);
else {
- sprintf(label_buf1, "/%d",
+ sprintf(label_buf1, "/%u",
nh_label->label[i]);
- strcat(label_buf, label_buf1);
+ strlcat(label_buf, label_buf1,
+ sizeof(label_buf));
}
}
num_labels++;
@@ -1716,7 +1741,6 @@ static int netlink_macfdb_change(struct sockaddr_nl *snl, struct nlmsghdr *h,
struct ndmsg *ndm;
struct interface *ifp;
struct zebra_if *zif;
- struct zebra_vrf *zvrf;
struct rtattr *tb[NDA_MAX + 1];
struct interface *br_if;
struct ethaddr mac;
@@ -1730,20 +1754,14 @@ static int netlink_macfdb_change(struct sockaddr_nl *snl, struct nlmsghdr *h,
ndm = NLMSG_DATA(h);
+ /* We only process macfdb notifications if EVPN is enabled */
+ if (!is_evpn_enabled())
+ return 0;
+
/* The interface should exist. */
ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(NS_DEFAULT),
ndm->ndm_ifindex);
- if (!ifp)
- return 0;
-
- /* Locate VRF corresponding to interface. We only process MAC
- * notifications
- * if EVPN is enabled on this VRF.
- */
- zvrf = vrf_info_lookup(ifp->vrf_id);
- if (!zvrf || !EVPN_ENABLED(zvrf))
- return 0;
- if (!ifp->info)
+ if (!ifp || !ifp->info)
return 0;
/* The interface should be something we're interested in. */
@@ -2033,7 +2051,6 @@ static int netlink_ipneigh_change(struct sockaddr_nl *snl, struct nlmsghdr *h,
struct ndmsg *ndm;
struct interface *ifp;
struct zebra_if *zif;
- struct zebra_vrf *zvrf;
struct rtattr *tb[NDA_MAX + 1];
struct interface *link_if;
struct ethaddr mac;
@@ -2045,20 +2062,14 @@ static int netlink_ipneigh_change(struct sockaddr_nl *snl, struct nlmsghdr *h,
ndm = NLMSG_DATA(h);
+ /* We only process neigh notifications if EVPN is enabled */
+ if (!is_evpn_enabled())
+ return 0;
+
/* The interface should exist. */
ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(NS_DEFAULT),
ndm->ndm_ifindex);
- if (!ifp)
- return 0;
-
- /* Locate VRF corresponding to interface. We only process neigh
- * notifications
- * if EVPN is enabled on this VRF.
- */
- zvrf = vrf_info_lookup(ifp->vrf_id);
- if (!zvrf || !EVPN_ENABLED(zvrf))
- return 0;
- if (!ifp->info)
+ if (!ifp || !ifp->info)
return 0;
/* Drop "permanent" entries. */