mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-04-28 17:42:20 +00:00
zebra: set connected route metric based on the devaddr metric
MACVLAN devices are typically used for applications such as VRR/VRRP that require a second MAC address (virtual). These devices have a corresponding SVI/VLAN device - root@TORC11:~# ip addr show vlan1002 39: vlan1002@bridge: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9152 qdisc noqueue master vrf1 state UP group default link/ether 00:02:00:00:00:2e brd ff:ff:ff:ff:ff:ff inet6 2001:aa:1::2/64 scope global valid_lft forever preferred_lft forever root@TORC11:~# ip addr show vlan1002-v0 40: vlan1002-v0@vlan1002: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9152 qdisc noqueue master vrf1 state UP group default link/ether 00:00:5e:00:01:01 brd ff:ff:ff:ff:ff:ff inet6 2001:aa:1::a/64 metric 1024 scope global valid_lft forever preferred_lft forever root@TORC11:~# The macvlan device is used primarily for RX (VR-IP/VR-MAC). And TX is via the SVI. To acheive that functionality the macvlan network's metric is set to a higher value. Zebra currently ignores the devaddr metric sent by the kernel and hardcodes it to 0. This commit eliminates that hardcoding. If the devaddr metric is available (METRIC_MAX) it is used for setting up the connected route otherwise we fallback to the dev/interface metric. Setting the macvlan metric to a higher value ensures that zebra will always select the connected route on the SVI (and subsequently use it for next hop resolution etc.) - root@TORC11:~# vtysh -c "show ip route vrf vrf1 2001:aa:1::/64" Routing entry for 2001:aa:1::/64 Known via "connected", distance 0, metric 1024, vrf vrf1 Last update 11:30:56 ago * directly connected, vlan1002-v0 Routing entry for 2001:aa:1::/64 Known via "connected", distance 0, metric 0, vrf vrf1, best Last update 11:30:56 ago * directly connected, vlan1002 root@TORC11:~# Ticket: CM-23511 Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
This commit is contained in:
parent
ec0ab5443f
commit
cde1af847e
69
include/linux/if_addr.h
Normal file
69
include/linux/if_addr.h
Normal file
@ -0,0 +1,69 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
|
||||
#ifndef __LINUX_IF_ADDR_H
|
||||
#define __LINUX_IF_ADDR_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/netlink.h>
|
||||
|
||||
struct ifaddrmsg {
|
||||
__u8 ifa_family;
|
||||
__u8 ifa_prefixlen; /* The prefix length */
|
||||
__u8 ifa_flags; /* Flags */
|
||||
__u8 ifa_scope; /* Address scope */
|
||||
__u32 ifa_index; /* Link index */
|
||||
};
|
||||
|
||||
/*
|
||||
* Important comment:
|
||||
* IFA_ADDRESS is prefix address, rather than local interface address.
|
||||
* It makes no difference for normally configured broadcast interfaces,
|
||||
* but for point-to-point IFA_ADDRESS is DESTINATION address,
|
||||
* local address is supplied in IFA_LOCAL attribute.
|
||||
*
|
||||
* IFA_FLAGS is a u32 attribute that extends the u8 field ifa_flags.
|
||||
* If present, the value from struct ifaddrmsg will be ignored.
|
||||
*/
|
||||
enum {
|
||||
IFA_UNSPEC,
|
||||
IFA_ADDRESS,
|
||||
IFA_LOCAL,
|
||||
IFA_LABEL,
|
||||
IFA_BROADCAST,
|
||||
IFA_ANYCAST,
|
||||
IFA_CACHEINFO,
|
||||
IFA_MULTICAST,
|
||||
IFA_FLAGS,
|
||||
IFA_RT_PRIORITY, /* u32, priority/metric for prefix route */
|
||||
__IFA_MAX,
|
||||
};
|
||||
|
||||
#define IFA_MAX (__IFA_MAX - 1)
|
||||
|
||||
/* ifa_flags */
|
||||
#define IFA_F_SECONDARY 0x01
|
||||
#define IFA_F_TEMPORARY IFA_F_SECONDARY
|
||||
|
||||
#define IFA_F_NODAD 0x02
|
||||
#define IFA_F_OPTIMISTIC 0x04
|
||||
#define IFA_F_DADFAILED 0x08
|
||||
#define IFA_F_HOMEADDRESS 0x10
|
||||
#define IFA_F_DEPRECATED 0x20
|
||||
#define IFA_F_TENTATIVE 0x40
|
||||
#define IFA_F_PERMANENT 0x80
|
||||
#define IFA_F_MANAGETEMPADDR 0x100
|
||||
#define IFA_F_NOPREFIXROUTE 0x200
|
||||
#define IFA_F_MCAUTOJOIN 0x400
|
||||
#define IFA_F_STABLE_PRIVACY 0x800
|
||||
|
||||
struct ifa_cacheinfo {
|
||||
__u32 ifa_prefered;
|
||||
__u32 ifa_valid;
|
||||
__u32 cstamp; /* created timestamp, hundredths of seconds */
|
||||
__u32 tstamp; /* updated timestamp, hundredths of seconds */
|
||||
};
|
||||
|
||||
/* backwards compatibility for userspace */
|
||||
#define IFA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrmsg))))
|
||||
#define IFA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifaddrmsg))
|
||||
|
||||
#endif
|
@ -1,4 +1,5 @@
|
||||
noinst_HEADERS += \
|
||||
include/linux/if_addr.h \
|
||||
include/linux/if_bridge.h \
|
||||
include/linux/if_link.h \
|
||||
include/linux/lwtunnel.h \
|
||||
|
9
lib/if.h
9
lib/if.h
@ -341,6 +341,8 @@ DECLARE_QOBJ_TYPE(interface)
|
||||
DECLARE_HOOK(if_add, (struct interface * ifp), (ifp))
|
||||
DECLARE_KOOH(if_del, (struct interface * ifp), (ifp))
|
||||
|
||||
#define METRIC_MAX (~0)
|
||||
|
||||
/* Connected address structure. */
|
||||
struct connected {
|
||||
/* Attached interface. */
|
||||
@ -388,6 +390,13 @@ struct connected {
|
||||
|
||||
/* Label for Linux 2.2.X and upper. */
|
||||
char *label;
|
||||
|
||||
/*
|
||||
* Used for setting the connected route's cost. If the metric
|
||||
* here is set to METRIC_MAX the connected route falls back to
|
||||
* "struct interface"
|
||||
*/
|
||||
uint32_t metric;
|
||||
};
|
||||
|
||||
/* Nbr Connected address structure. */
|
||||
|
@ -209,6 +209,7 @@ void connected_up(struct interface *ifp, struct connected *ifc)
|
||||
.ifindex = ifp->ifindex,
|
||||
.vrf_id = ifp->vrf_id,
|
||||
};
|
||||
uint32_t metric;
|
||||
|
||||
if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL))
|
||||
return;
|
||||
@ -243,11 +244,13 @@ void connected_up(struct interface *ifp, struct connected *ifc)
|
||||
break;
|
||||
}
|
||||
|
||||
metric = (ifc->metric < (uint32_t)METRIC_MAX) ?
|
||||
ifc->metric : ifp->metric;
|
||||
rib_add(afi, SAFI_UNICAST, ifp->vrf_id, ZEBRA_ROUTE_CONNECT, 0, 0, &p,
|
||||
NULL, &nh, RT_TABLE_MAIN, ifp->metric, 0, 0, 0);
|
||||
NULL, &nh, RT_TABLE_MAIN, metric, 0, 0, 0);
|
||||
|
||||
rib_add(afi, SAFI_MULTICAST, ifp->vrf_id, ZEBRA_ROUTE_CONNECT, 0, 0, &p,
|
||||
NULL, &nh, RT_TABLE_MAIN, ifp->metric, 0, 0, 0);
|
||||
NULL, &nh, RT_TABLE_MAIN, metric, 0, 0, 0);
|
||||
|
||||
if (IS_ZEBRA_DEBUG_RIB_DETAILED) {
|
||||
char buf[PREFIX_STRLEN];
|
||||
@ -276,7 +279,7 @@ void connected_up(struct interface *ifp, struct connected *ifc)
|
||||
/* Add connected IPv4 route to the interface. */
|
||||
void connected_add_ipv4(struct interface *ifp, int flags, struct in_addr *addr,
|
||||
uint16_t prefixlen, struct in_addr *broad,
|
||||
const char *label)
|
||||
const char *label, uint32_t metric)
|
||||
{
|
||||
struct prefix_ipv4 *p;
|
||||
struct connected *ifc;
|
||||
@ -288,6 +291,7 @@ void connected_add_ipv4(struct interface *ifp, int flags, struct in_addr *addr,
|
||||
ifc = connected_new();
|
||||
ifc->ifp = ifp;
|
||||
ifc->flags = flags;
|
||||
ifc->metric = metric;
|
||||
/* If we get a notification from the kernel,
|
||||
* we can safely assume the address is known to the kernel */
|
||||
SET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED);
|
||||
@ -500,7 +504,7 @@ void connected_delete_ipv4(struct interface *ifp, int flags,
|
||||
/* Add connected IPv6 route to the interface. */
|
||||
void connected_add_ipv6(struct interface *ifp, int flags, struct in6_addr *addr,
|
||||
struct in6_addr *broad, uint16_t prefixlen,
|
||||
const char *label)
|
||||
const char *label, uint32_t metric)
|
||||
{
|
||||
struct prefix_ipv6 *p;
|
||||
struct connected *ifc;
|
||||
@ -512,6 +516,7 @@ void connected_add_ipv6(struct interface *ifp, int flags, struct in6_addr *addr,
|
||||
ifc = connected_new();
|
||||
ifc->ifp = ifp;
|
||||
ifc->flags = flags;
|
||||
ifc->metric = metric;
|
||||
/* If we get a notification from the kernel,
|
||||
* we can safely assume the address is known to the kernel */
|
||||
SET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED);
|
||||
|
@ -36,7 +36,8 @@ extern struct connected *connected_check_ptp(struct interface *ifp,
|
||||
|
||||
extern void connected_add_ipv4(struct interface *ifp, int flags,
|
||||
struct in_addr *addr, uint16_t prefixlen,
|
||||
struct in_addr *broad, const char *label);
|
||||
struct in_addr *broad, const char *label,
|
||||
uint32_t metric);
|
||||
|
||||
extern void connected_delete_ipv4(struct interface *ifp, int flags,
|
||||
struct in_addr *addr, uint16_t prefixlen,
|
||||
@ -49,7 +50,8 @@ extern void connected_down(struct interface *ifp, struct connected *ifc);
|
||||
|
||||
extern void connected_add_ipv6(struct interface *ifp, int flags,
|
||||
struct in6_addr *address, struct in6_addr *broad,
|
||||
uint16_t prefixlen, const char *label);
|
||||
uint16_t prefixlen, const char *label,
|
||||
uint32_t metric);
|
||||
extern void connected_delete_ipv6(struct interface *ifp,
|
||||
struct in6_addr *address,
|
||||
struct in6_addr *broad, uint16_t prefixlen);
|
||||
|
@ -236,7 +236,8 @@ static int if_getaddrs(void)
|
||||
}
|
||||
|
||||
connected_add_ipv4(ifp, flags, &addr->sin_addr,
|
||||
prefixlen, dest_pnt, NULL);
|
||||
prefixlen, dest_pnt, NULL,
|
||||
METRIC_MAX);
|
||||
}
|
||||
if (ifap->ifa_addr->sa_family == AF_INET6) {
|
||||
struct sockaddr_in6 *addr;
|
||||
@ -258,7 +259,7 @@ static int if_getaddrs(void)
|
||||
#endif
|
||||
|
||||
connected_add_ipv6(ifp, flags, &addr->sin6_addr, NULL,
|
||||
prefixlen, NULL);
|
||||
prefixlen, NULL, METRIC_MAX);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -302,10 +302,11 @@ static int if_get_addr(struct interface *ifp, struct sockaddr *addr,
|
||||
/* Set address to the interface. */
|
||||
if (af == AF_INET)
|
||||
connected_add_ipv4(ifp, flags, &SIN(addr)->sin_addr, prefixlen,
|
||||
(struct in_addr *)dest_pnt, label);
|
||||
(struct in_addr *)dest_pnt, label,
|
||||
METRIC_MAX);
|
||||
else if (af == AF_INET6)
|
||||
connected_add_ipv6(ifp, flags, &SIN6(addr)->sin6_addr, NULL,
|
||||
prefixlen, label);
|
||||
prefixlen, label, METRIC_MAX);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -924,6 +924,7 @@ int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup)
|
||||
uint8_t flags = 0;
|
||||
char *label = NULL;
|
||||
struct zebra_ns *zns;
|
||||
uint32_t metric = METRIC_MAX;
|
||||
|
||||
zns = zebra_ns_lookup(ns_id);
|
||||
ifa = NLMSG_DATA(h);
|
||||
@ -1032,6 +1033,9 @@ int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup)
|
||||
if (label && strcmp(ifp->name, label) == 0)
|
||||
label = NULL;
|
||||
|
||||
if (tb[IFA_RT_PRIORITY])
|
||||
metric = *(uint32_t *)RTA_DATA(tb[IFA_RT_PRIORITY]);
|
||||
|
||||
/* Register interface address to the interface. */
|
||||
if (ifa->ifa_family == AF_INET) {
|
||||
if (ifa->ifa_prefixlen > IPV4_MAX_BITLEN) {
|
||||
@ -1044,7 +1048,8 @@ int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup)
|
||||
if (h->nlmsg_type == RTM_NEWADDR)
|
||||
connected_add_ipv4(ifp, flags, (struct in_addr *)addr,
|
||||
ifa->ifa_prefixlen,
|
||||
(struct in_addr *)broad, label);
|
||||
(struct in_addr *)broad, label,
|
||||
metric);
|
||||
else
|
||||
connected_delete_ipv4(
|
||||
ifp, flags, (struct in_addr *)addr,
|
||||
@ -1070,7 +1075,8 @@ int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup)
|
||||
connected_add_ipv6(ifp, flags,
|
||||
(struct in6_addr *)addr,
|
||||
(struct in6_addr *)broad,
|
||||
ifa->ifa_prefixlen, label);
|
||||
ifa->ifa_prefixlen, label,
|
||||
metric);
|
||||
} else
|
||||
connected_delete_ipv6(ifp, (struct in6_addr *)addr,
|
||||
(struct in6_addr *)broad,
|
||||
|
@ -906,7 +906,8 @@ int ifam_read(struct ifa_msghdr *ifam)
|
||||
connected_add_ipv4(ifp, flags, &addr.sin.sin_addr,
|
||||
ip_masklen(mask.sin.sin_addr),
|
||||
&brd.sin.sin_addr,
|
||||
(isalias ? ifname : NULL));
|
||||
(isalias ? ifname : NULL),
|
||||
METRIC_MAX);
|
||||
else
|
||||
connected_delete_ipv4(ifp, flags, &addr.sin.sin_addr,
|
||||
ip_masklen(mask.sin.sin_addr),
|
||||
@ -923,7 +924,8 @@ int ifam_read(struct ifa_msghdr *ifam)
|
||||
connected_add_ipv6(ifp, flags, &addr.sin6.sin6_addr,
|
||||
NULL,
|
||||
ip6_masklen(mask.sin6.sin6_addr),
|
||||
(isalias ? ifname : NULL));
|
||||
(isalias ? ifname : NULL),
|
||||
METRIC_MAX);
|
||||
else
|
||||
connected_delete_ipv6(ifp, &addr.sin6.sin6_addr, NULL,
|
||||
ip6_masklen(mask.sin6.sin6_addr));
|
||||
|
Loading…
Reference in New Issue
Block a user