]> git.proxmox.com Git - mirror_frr.git/blobdiff - zebra/if_netlink.c
Merge remote-tracking branch 'frr/master' into warnings
[mirror_frr.git] / zebra / if_netlink.c
index 8f6e31cfa8864a32c7ef868c4b9f9eddd026398f..184c5a4fa556c766cd7cbca3e8aa5cc631f2d766 100644 (file)
@@ -52,6 +52,7 @@
 #include "vrf.h"
 #include "vrf_int.h"
 #include "mpls.h"
+#include "lib_errors.h"
 
 #include "vty.h"
 #include "zebra/zserv.h"
@@ -66,6 +67,7 @@
 #include "zebra/zebra_mpls.h"
 #include "zebra/kernel_netlink.h"
 #include "zebra/if_netlink.h"
+#include "zebra/zebra_errors.h"
 
 extern struct zebra_privs_t zserv_privs;
 
@@ -79,9 +81,9 @@ static void set_ifindex(struct interface *ifp, ifindex_t ifi_index,
        if (((oifp = if_lookup_by_index_per_ns(zns, ifi_index)) != NULL)
            && (oifp != ifp)) {
                if (ifi_index == IFINDEX_INTERNAL)
-                       zlog_err(
-                               "Netlink is setting interface %s ifindex to reserved "
-                               "internal value %u",
+                       flog_err(
+                               LIB_ERR_INTERFACE,
+                               "Netlink is setting interface %s ifindex to reserved internal value %u",
                                ifp->name, ifi_index);
                else {
                        if (IS_ZEBRA_DEBUG_KERNEL)
@@ -89,9 +91,9 @@ static void set_ifindex(struct interface *ifp, ifindex_t ifi_index,
                                        "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!",
+                               flog_err(
+                                       LIB_ERR_INTERFACE,
+                                       "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);
                }
@@ -111,8 +113,8 @@ static void netlink_interface_update_hw_addr(struct rtattr **tb,
                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);
+                       zlog_debug("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]),
@@ -258,6 +260,8 @@ static void netlink_determine_zebra_iftype(char *kind, zebra_iftype_t *zif_type)
                *zif_type = ZEBRA_IF_VXLAN;
        else if (strcmp(kind, "macvlan") == 0)
                *zif_type = ZEBRA_IF_MACVLAN;
+       else if (strcmp(kind, "veth") == 0)
+               *zif_type = ZEBRA_IF_VETH;
 }
 
 #define parse_rtattr_nested(tb, max, rta)                                      \
@@ -309,8 +313,8 @@ static void netlink_vrf_change(struct nlmsghdr *h, struct rtattr *tb,
                vrf = vrf_get((vrf_id_t)ifi->ifi_index,
                              name); // It would create vrf
                if (!vrf) {
-                       zlog_err("VRF %s id %u not created", name,
-                                ifi->ifi_index);
+                       flog_err(LIB_ERR_INTERFACE, "VRF %s id %u not created",
+                                 name, ifi->ifi_index);
                        return;
                }
 
@@ -331,8 +335,9 @@ static void netlink_vrf_change(struct nlmsghdr *h, struct rtattr *tb,
 
                /* Enable the created VRF. */
                if (!vrf_enable(vrf)) {
-                       zlog_err("Failed to enable VRF %s id %u", name,
-                                ifi->ifi_index);
+                       flog_err(LIB_ERR_INTERFACE,
+                                 "Failed to enable VRF %s id %u", name,
+                                 ifi->ifi_index);
                        return;
                }
 
@@ -345,7 +350,8 @@ static void netlink_vrf_change(struct nlmsghdr *h, struct rtattr *tb,
                vrf = vrf_lookup_by_id((vrf_id_t)ifi->ifi_index);
 
                if (!vrf) {
-                       zlog_warn("%s: vrf not found", __func__);
+                       flog_warn(ZEBRA_ERR_VRF_NOT_FOUND, "%s: vrf not found",
+                                 __func__);
                        return;
                }
 
@@ -373,20 +379,20 @@ static int get_iflink_speed(struct interface *interface)
        ifdata.ifr_data = (caddr_t)&ecmd;
 
        /* use ioctl to get IP address of an interface */
-       if (zserv_privs.change(ZPRIVS_RAISE))
-               zlog_err("Can't raise privileges");
-       sd = vrf_socket(PF_INET, SOCK_DGRAM, IPPROTO_IP, interface->vrf_id,
-                       NULL);
-       if (sd < 0) {
-               if (IS_ZEBRA_DEBUG_KERNEL)
-                       zlog_debug("Failure to read interface %s speed: %d %s",
-                                  ifname, errno, safe_strerror(errno));
-               return 0;
-       }
+       frr_elevate_privs(&zserv_privs) {
+               sd = vrf_socket(PF_INET, SOCK_DGRAM, IPPROTO_IP,
+                               interface->vrf_id,
+                               NULL);
+               if (sd < 0) {
+                       if (IS_ZEBRA_DEBUG_KERNEL)
+                               zlog_debug("Failure to read interface %s speed: %d %s",
+                                          ifname, errno, safe_strerror(errno));
+                       return 0;
+               }
        /* Get the current link state for the interface */
-       rc = vrf_ioctl(interface->vrf_id, sd, SIOCETHTOOL, (char *)&ifdata);
-       if (zserv_privs.change(ZPRIVS_LOWER))
-               zlog_err("Can't lower privileges");
+               rc = vrf_ioctl(interface->vrf_id, sd, SIOCETHTOOL,
+                              (char *)&ifdata);
+       }
        if (rc < 0) {
                if (IS_ZEBRA_DEBUG_KERNEL)
                        zlog_debug(
@@ -527,7 +533,8 @@ static int netlink_bridge_interface(struct nlmsghdr *h, int len, ns_id_t ns_id,
        /* The interface should already be known, if not discard. */
        ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(ns_id), ifi->ifi_index);
        if (!ifp) {
-               zlog_warn("Cannot find bridge IF %s(%u)", name, ifi->ifi_index);
+               zlog_debug("Cannot find bridge IF %s(%u)", name,
+                          ifi->ifi_index);
                return 0;
        }
        if (!IS_ZEBRA_IF_VXLAN(ifp))
@@ -673,7 +680,7 @@ static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup)
                SET_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK);
 
        /* Update link. */
-       zebra_if_update_link(ifp, link_ifindex);
+       zebra_if_update_link(ifp, link_ifindex, ns_id);
 
        /* Hardware type and address. */
        ifp->ll_type = netlink_to_zebra_link_type(ifi->ifi_type);
@@ -891,8 +898,13 @@ int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup)
        zns = zebra_ns_lookup(ns_id);
        ifa = NLMSG_DATA(h);
 
-       if (ifa->ifa_family != AF_INET && ifa->ifa_family != AF_INET6)
+       if (ifa->ifa_family != AF_INET && ifa->ifa_family != AF_INET6) {
+               flog_warn(
+                       ZEBRA_ERR_UNKNOWN_FAMILY,
+                       "Invalid address family: %u received from kernel interface addr change: %u",
+                       ifa->ifa_family, h->nlmsg_type);
                return 0;
+       }
 
        if (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR)
                return 0;
@@ -911,7 +923,8 @@ int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup)
 
        ifp = if_lookup_by_index_per_ns(zns, ifa->ifa_index);
        if (ifp == NULL) {
-               zlog_err(
+               flog_err(
+                       LIB_ERR_INTERFACE,
                        "netlink_interface_addr can't find interface by index %d",
                        ifa->ifa_index);
                return -1;
@@ -991,6 +1004,12 @@ int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup)
 
        /* Register interface address to the interface. */
        if (ifa->ifa_family == AF_INET) {
+               if (ifa->ifa_prefixlen > IPV4_MAX_BITLEN) {
+                       zlog_err(
+                               "Invalid prefix length: %u received from kernel interface addr change: %u",
+                               ifa->ifa_prefixlen, h->nlmsg_type);
+                       return -1;
+               }
                if (h->nlmsg_type == RTM_NEWADDR)
                        connected_add_ipv4(ifp, flags, (struct in_addr *)addr,
                                           ifa->ifa_prefixlen,
@@ -1001,6 +1020,12 @@ int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup)
                                ifa->ifa_prefixlen, (struct in_addr *)broad);
        }
        if (ifa->ifa_family == AF_INET6) {
+               if (ifa->ifa_prefixlen > IPV6_MAX_BITLEN) {
+                       zlog_err(
+                               "Invalid prefix length: %u received from kernel interface addr change: %u",
+                               ifa->ifa_prefixlen, h->nlmsg_type);
+                       return -1;
+               }
                if (h->nlmsg_type == RTM_NEWADDR) {
                        /* Only consider valid addresses; we'll not get a
                         * notification from
@@ -1023,67 +1048,6 @@ int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup)
        return 0;
 }
 
-/* helper function called by if_netlink_change
- * to delete interfaces in case the interface moved
- * to an other netns
- */
-static void if_netlink_check_ifp_instance_consistency(uint16_t cmd,
-                                                    struct interface *ifp,
-                                                    ns_id_t ns_id)
-{
-       struct interface *other_ifp;
-
-       /*
-        * look if interface name is also found on other netns
-        * - only if vrf backend is netns
-        * - do not concern lo interface
-        * - then remove previous one
-        * - for new link case, check found interface is not active
-        */
-       if (!vrf_is_backend_netns() ||
-           !strcmp(ifp->name, "lo"))
-               return;
-       other_ifp = if_lookup_by_name_not_ns(ns_id, ifp->name);
-       if (!other_ifp)
-               return;
-       /* because previous interface may be inactive,
-        * interface is moved back to default vrf
-        * then one may find the same pointer; ignore
-        */
-       if (other_ifp == ifp)
-               return;
-       if ((cmd == RTM_NEWLINK)
-           && (CHECK_FLAG(other_ifp->status, ZEBRA_INTERFACE_ACTIVE)))
-               return;
-       if (IS_ZEBRA_DEBUG_KERNEL && cmd == RTM_NEWLINK) {
-               zlog_debug("RTM_NEWLINK %s(%u, VRF %u) replaces %s(%u, VRF %u)\n",
-                          ifp->name,
-                          ifp->ifindex,
-                          ifp->vrf_id,
-                          other_ifp->name,
-                          other_ifp->ifindex,
-                          other_ifp->vrf_id);
-       } else  if (IS_ZEBRA_DEBUG_KERNEL && cmd == RTM_DELLINK) {
-               zlog_debug("RTM_DELLINK %s(%u, VRF %u) is replaced by %s(%u, VRF %u)\n",
-                          ifp->name,
-                          ifp->ifindex,
-                          ifp->vrf_id,
-                          other_ifp->name,
-                          other_ifp->ifindex,
-                          other_ifp->vrf_id);
-       }
-       /* the found interface replaces the current one
-        * remove it
-        */
-       if (cmd == RTM_DELLINK)
-               if_delete(ifp);
-       else
-               if_delete(other_ifp);
-       /* the found interface is replaced by the current one
-        * suppress it
-        */
-}
-
 int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
 {
        int len;
@@ -1109,8 +1073,17 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
        /* assume if not default zns, then new VRF */
        if (!(h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK)) {
                /* If this is not link add/delete message so print warning. */
-               zlog_warn("netlink_link_change: wrong kernel message %d",
-                         h->nlmsg_type);
+               zlog_debug("netlink_link_change: wrong kernel message %d",
+                          h->nlmsg_type);
+               return 0;
+       }
+
+       if (!(ifi->ifi_family == AF_UNSPEC || ifi->ifi_family == AF_BRIDGE
+             || ifi->ifi_family == AF_INET6)) {
+               flog_warn(
+                       ZEBRA_ERR_UNKNOWN_FAMILY,
+                       "Invalid address family: %u received from kernel link change: %u",
+                       ifi->ifi_family, h->nlmsg_type);
                return 0;
        }
 
@@ -1218,6 +1191,12 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
                        /* Update interface information. */
                        set_ifindex(ifp, ifi->ifi_index, zns);
                        ifp->flags = ifi->ifi_flags & 0x0000fffff;
+                       if (!tb[IFLA_MTU]) {
+                               zlog_debug(
+                                       "RTM_NEWLINK for interface %s(%u) without MTU set",
+                                       name, ifi->ifi_index);
+                               return 0;
+                       }
                        ifp->mtu6 = ifp->mtu = *(int *)RTA_DATA(tb[IFLA_MTU]);
                        ifp->metric = 0;
                        ifp->ptm_status = ZEBRA_PTM_STATUS_UNKNOWN;
@@ -1229,7 +1208,7 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
                                         ZEBRA_INTERFACE_VRF_LOOPBACK);
 
                        /* Update link. */
-                       zebra_if_update_link(ifp, link_ifindex);
+                       zebra_if_update_link(ifp, link_ifindex, ns_id);
 
                        netlink_interface_update_hw_addr(tb, ifp);
 
@@ -1243,8 +1222,6 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
                        if (IS_ZEBRA_IF_BRIDGE_SLAVE(ifp))
                                zebra_l2if_update_bridge_slave(ifp,
                                                               bridge_ifindex);
-                       if_netlink_check_ifp_instance_consistency(RTM_NEWLINK,
-                                                                 ifp, ns_id);
                } else if (ifp->vrf_id != vrf_id) {
                        /* VRF change for an interface. */
                        if (IS_ZEBRA_DEBUG_KERNEL)
@@ -1267,6 +1244,12 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
                                        bridge_ifindex, ifi->ifi_flags);
 
                        set_ifindex(ifp, ifi->ifi_index, zns);
+                       if (!tb[IFLA_MTU]) {
+                               zlog_debug(
+                                       "RTM_NEWLINK for interface %s(%u) without MTU set",
+                                       name, ifi->ifi_index);
+                               return 0;
+                       }
                        ifp->mtu6 = ifp->mtu = *(int *)RTA_DATA(tb[IFLA_MTU]);
                        ifp->metric = 0;
 
@@ -1312,14 +1295,14 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
                        if (IS_ZEBRA_IF_BRIDGE_SLAVE(ifp) || was_bridge_slave)
                                zebra_l2if_update_bridge_slave(ifp,
                                                               bridge_ifindex);
-                       if_netlink_check_ifp_instance_consistency(RTM_NEWLINK,
-                                                                 ifp, ns_id);
                }
        } else {
                /* Delete interface notification from kernel */
                if (ifp == NULL) {
-                       zlog_warn("RTM_DELLINK for unknown interface %s(%u)",
-                                 name, ifi->ifi_index);
+                       if (IS_ZEBRA_DEBUG_KERNEL)
+                               zlog_debug(
+                                       "RTM_DELLINK for unknown interface %s(%u)",
+                                       name, ifi->ifi_index);
                        return 0;
                }
 
@@ -1337,8 +1320,6 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
 
                if (!IS_ZEBRA_IF_VRF(ifp))
                        if_delete_update(ifp);
-               if_netlink_check_ifp_instance_consistency(RTM_DELLINK,
-                                                         ifp, ns_id);
        }
 
        return 0;