]> git.proxmox.com Git - mirror_frr.git/blobdiff - zebra/if_netlink.c
zebra, lib: fix the ZEBRA_INTERFACE_VRF_UPDATE zapi message
[mirror_frr.git] / zebra / if_netlink.c
index 184c5a4fa556c766cd7cbca3e8aa5cc631f2d766..f4bd193569b89444173a5f14e1248324f0d7ee7a 100644 (file)
@@ -82,7 +82,7 @@ static void set_ifindex(struct interface *ifp, ifindex_t ifi_index,
            && (oifp != ifp)) {
                if (ifi_index == IFINDEX_INTERNAL)
                        flog_err(
-                               LIB_ERR_INTERFACE,
+                               EC_LIB_INTERFACE,
                                "Netlink is setting interface %s ifindex to reserved internal value %u",
                                ifp->name, ifi_index);
                else {
@@ -92,7 +92,7 @@ static void set_ifindex(struct interface *ifp, ifindex_t ifi_index,
                                        ifi_index, oifp->name, ifp->name);
                        if (if_is_up(oifp))
                                flog_err(
-                                       LIB_ERR_INTERFACE,
+                                       EC_LIB_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);
@@ -243,7 +243,8 @@ static enum zebra_link_type netlink_to_zebra_link_type(unsigned int hwt)
        }
 }
 
-static void netlink_determine_zebra_iftype(char *kind, zebra_iftype_t *zif_type)
+static void netlink_determine_zebra_iftype(const char *kind,
+                                          zebra_iftype_t *zif_type)
 {
        *zif_type = ZEBRA_IF_OTHER;
 
@@ -262,6 +263,10 @@ static void netlink_determine_zebra_iftype(char *kind, zebra_iftype_t *zif_type)
                *zif_type = ZEBRA_IF_MACVLAN;
        else if (strcmp(kind, "veth") == 0)
                *zif_type = ZEBRA_IF_VETH;
+       else if (strcmp(kind, "bond") == 0)
+               *zif_type = ZEBRA_IF_BOND;
+       else if (strcmp(kind, "bond_slave") == 0)
+               *zif_type = ZEBRA_IF_BOND_SLAVE;
 }
 
 #define parse_rtattr_nested(tb, max, rta)                                      \
@@ -313,8 +318,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) {
-                       flog_err(LIB_ERR_INTERFACE, "VRF %s id %u not created",
-                                 name, ifi->ifi_index);
+                       flog_err(EC_LIB_INTERFACE, "VRF %s id %u not created",
+                                name, ifi->ifi_index);
                        return;
                }
 
@@ -335,9 +340,9 @@ static void netlink_vrf_change(struct nlmsghdr *h, struct rtattr *tb,
 
                /* Enable the created VRF. */
                if (!vrf_enable(vrf)) {
-                       flog_err(LIB_ERR_INTERFACE,
-                                 "Failed to enable VRF %s id %u", name,
-                                 ifi->ifi_index);
+                       flog_err(EC_LIB_INTERFACE,
+                                "Failed to enable VRF %s id %u", name,
+                                ifi->ifi_index);
                        return;
                }
 
@@ -350,7 +355,7 @@ static void netlink_vrf_change(struct nlmsghdr *h, struct rtattr *tb,
                vrf = vrf_lookup_by_id((vrf_id_t)ifi->ifi_index);
 
                if (!vrf) {
-                       flog_warn(ZEBRA_ERR_VRF_NOT_FOUND, "%s: vrf not found",
+                       flog_warn(EC_ZEBRA_VRF_NOT_FOUND, "%s: vrf not found",
                                  __func__);
                        return;
                }
@@ -585,6 +590,8 @@ static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup)
        zebra_slave_iftype_t zif_slave_type = ZEBRA_IF_SLAVE_NONE;
        ifindex_t bridge_ifindex = IFINDEX_INTERNAL;
        ifindex_t link_ifindex = IFINDEX_INTERNAL;
+       ifindex_t bond_ifindex = IFINDEX_INTERNAL;
+       struct zebra_if *zif;
 
        zns = zebra_ns_lookup(ns_id);
        ifi = NLMSG_DATA(h);
@@ -634,7 +641,10 @@ static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup)
                if (linkinfo[IFLA_INFO_SLAVE_KIND])
                        slave_kind = RTA_DATA(linkinfo[IFLA_INFO_SLAVE_KIND]);
 
-               netlink_determine_zebra_iftype(kind, &zif_type);
+               if ((slave_kind != NULL) && strcmp(slave_kind, "bond") == 0)
+                       netlink_determine_zebra_iftype("bond_slave", &zif_type);
+               else
+                       netlink_determine_zebra_iftype(kind, &zif_type);
        }
 
        /* If VRF, create the VRF structure itself. */
@@ -652,6 +662,9 @@ static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup)
                        zif_slave_type = ZEBRA_IF_SLAVE_BRIDGE;
                        bridge_ifindex =
                                *(ifindex_t *)RTA_DATA(tb[IFLA_MASTER]);
+               } else if (slave_kind && (strcmp(slave_kind, "bond") == 0)) {
+                       zif_slave_type = ZEBRA_IF_SLAVE_BOND;
+                       bond_ifindex = *(ifindex_t *)RTA_DATA(tb[IFLA_MASTER]);
                } else
                        zif_slave_type = ZEBRA_IF_SLAVE_OTHER;
        }
@@ -663,7 +676,7 @@ static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup)
                link_ifindex = *(ifindex_t *)RTA_DATA(tb[IFLA_LINK]);
 
        /* Add interface. */
-       ifp = if_get_by_name(name, vrf_id, 0);
+       ifp = if_get_by_name(name, vrf_id);
        set_ifindex(ifp, ifi->ifi_index, zns);
        ifp->flags = ifi->ifi_flags & 0x0000fffff;
        ifp->mtu6 = ifp->mtu = *(uint32_t *)RTA_DATA(tb[IFLA_MTU]);
@@ -679,8 +692,14 @@ static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup)
        if (IS_ZEBRA_IF_VRF(ifp))
                SET_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK);
 
-       /* Update link. */
-       zebra_if_update_link(ifp, link_ifindex, ns_id);
+       /*
+        * Just set the @link/lower-device ifindex. During nldump interfaces are
+        * not ordered in any fashion so we may end up getting upper devices
+        * before lower devices. We will setup the real linkage once the dump
+        * is complete.
+        */
+       zif = (struct zebra_if *)ifp->info;
+       zif->link_ifindex = link_ifindex;
 
        /* Hardware type and address. */
        ifp->ll_type = netlink_to_zebra_link_type(ifi->ifi_type);
@@ -693,13 +712,15 @@ static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup)
        netlink_interface_update_l2info(ifp, linkinfo[IFLA_INFO_DATA], 1);
        if (IS_ZEBRA_IF_BRIDGE_SLAVE(ifp))
                zebra_l2if_update_bridge_slave(ifp, bridge_ifindex);
+       else if (IS_ZEBRA_IF_BOND_SLAVE(ifp))
+               zebra_l2if_update_bond_slave(ifp, bond_ifindex);
 
        return 0;
 }
 
 /* Request for specific interface or address information from the kernel */
-static int netlink_request_intf_addr(struct zebra_ns *zns, int family, int type,
-                                    uint32_t filter_mask)
+static int netlink_request_intf_addr(struct nlsock *netlink_cmd, int family,
+                                    int type, uint32_t filter_mask)
 {
        struct {
                struct nlmsghdr n;
@@ -717,57 +738,65 @@ static int netlink_request_intf_addr(struct zebra_ns *zns, int family, int type,
        if (filter_mask)
                addattr32(&req.n, sizeof(req), IFLA_EXT_MASK, filter_mask);
 
-       return netlink_request(&zns->netlink_cmd, &req.n);
+       return netlink_request(netlink_cmd, &req.n);
 }
 
 /* Interface lookup by netlink socket. */
 int interface_lookup_netlink(struct zebra_ns *zns)
 {
        int ret;
+       struct zebra_dplane_info dp_info;
+       struct nlsock *netlink_cmd = &zns->netlink_cmd;
+
+       /* Capture key info from ns struct */
+       zebra_dplane_info_from_zns(&dp_info, zns, true /*is_cmd*/);
 
        /* Get interface information. */
-       ret = netlink_request_intf_addr(zns, AF_PACKET, RTM_GETLINK, 0);
+       ret = netlink_request_intf_addr(netlink_cmd, AF_PACKET, RTM_GETLINK, 0);
        if (ret < 0)
                return ret;
-       ret = netlink_parse_info(netlink_interface, &zns->netlink_cmd, zns, 0,
+       ret = netlink_parse_info(netlink_interface, netlink_cmd, &dp_info, 0,
                                 1);
        if (ret < 0)
                return ret;
 
        /* Get interface information - for bridge interfaces. */
-       ret = netlink_request_intf_addr(zns, AF_BRIDGE, RTM_GETLINK,
+       ret = netlink_request_intf_addr(netlink_cmd, AF_BRIDGE, RTM_GETLINK,
                                        RTEXT_FILTER_BRVLAN);
        if (ret < 0)
                return ret;
-       ret = netlink_parse_info(netlink_interface, &zns->netlink_cmd, zns, 0,
+       ret = netlink_parse_info(netlink_interface, netlink_cmd, &dp_info, 0,
                                 0);
        if (ret < 0)
                return ret;
 
        /* Get interface information - for bridge interfaces. */
-       ret = netlink_request_intf_addr(zns, AF_BRIDGE, RTM_GETLINK,
+       ret = netlink_request_intf_addr(netlink_cmd, AF_BRIDGE, RTM_GETLINK,
                                        RTEXT_FILTER_BRVLAN);
        if (ret < 0)
                return ret;
-       ret = netlink_parse_info(netlink_interface, &zns->netlink_cmd, zns, 0,
+       ret = netlink_parse_info(netlink_interface, netlink_cmd, &dp_info, 0,
                                 0);
        if (ret < 0)
                return ret;
 
+       /* fixup linkages */
+       zebra_if_update_all_links();
+
        /* Get IPv4 address of the interfaces. */
-       ret = netlink_request_intf_addr(zns, AF_INET, RTM_GETADDR, 0);
+       ret = netlink_request_intf_addr(netlink_cmd, AF_INET, RTM_GETADDR, 0);
        if (ret < 0)
                return ret;
-       ret = netlink_parse_info(netlink_interface_addr, &zns->netlink_cmd, zns,
+       ret = netlink_parse_info(netlink_interface_addr, netlink_cmd, &dp_info,
                                 0, 1);
        if (ret < 0)
                return ret;
 
        /* Get IPv6 address of the interfaces. */
-       ret = netlink_request_intf_addr(zns, AF_INET6, RTM_GETADDR, 0);
+       ret = netlink_request_intf_addr(netlink_cmd, AF_INET6, RTM_GETADDR, 0);
        if (ret < 0)
                return ret;
-       ret = netlink_parse_info(netlink_interface_addr, &zns->netlink_cmd, zns,
+       ret = netlink_parse_info(netlink_interface_addr, netlink_cmd, &dp_info,
                                 0, 1);
        if (ret < 0)
                return ret;
@@ -900,9 +929,9 @@ int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup)
 
        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);
+                       EC_ZEBRA_UNKNOWN_FAMILY,
+                       "Invalid address family: %u received from kernel interface addr change: %s",
+                       ifa->ifa_family, nl_msg_type_to_str(h->nlmsg_type));
                return 0;
        }
 
@@ -924,7 +953,7 @@ 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) {
                flog_err(
-                       LIB_ERR_INTERFACE,
+                       EC_LIB_INTERFACE,
                        "netlink_interface_addr can't find interface by index %d",
                        ifa->ifa_index);
                return -1;
@@ -1006,8 +1035,9 @@ int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup)
        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);
+                               "Invalid prefix length: %u received from kernel interface addr change: %s",
+                               ifa->ifa_prefixlen,
+                               nl_msg_type_to_str(h->nlmsg_type));
                        return -1;
                }
                if (h->nlmsg_type == RTM_NEWADDR)
@@ -1022,8 +1052,9 @@ int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup)
        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);
+                               "Invalid prefix length: %u received from kernel interface addr change: %s",
+                               ifa->ifa_prefixlen,
+                               nl_msg_type_to_str(h->nlmsg_type));
                        return -1;
                }
                if (h->nlmsg_type == RTM_NEWADDR) {
@@ -1064,6 +1095,7 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
        zebra_iftype_t zif_type = ZEBRA_IF_OTHER;
        zebra_slave_iftype_t zif_slave_type = ZEBRA_IF_SLAVE_NONE;
        ifindex_t bridge_ifindex = IFINDEX_INTERNAL;
+       ifindex_t bond_ifindex = IFINDEX_INTERNAL;
        ifindex_t link_ifindex = IFINDEX_INTERNAL;
 
 
@@ -1073,17 +1105,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_debug("netlink_link_change: wrong kernel message %d",
-                          h->nlmsg_type);
+               zlog_debug("netlink_link_change: wrong kernel message %s",
+                          nl_msg_type_to_str(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);
+                       EC_ZEBRA_UNKNOWN_FAMILY,
+                       "Invalid address family: %u received from kernel link change: %s",
+                       ifi->ifi_family, nl_msg_type_to_str(h->nlmsg_type));
                return 0;
        }
 
@@ -1163,6 +1195,11 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
                                zif_slave_type = ZEBRA_IF_SLAVE_BRIDGE;
                                bridge_ifindex =
                                        *(ifindex_t *)RTA_DATA(tb[IFLA_MASTER]);
+                       } else if (slave_kind
+                                  && (strcmp(slave_kind, "bond") == 0)) {
+                               zif_slave_type = ZEBRA_IF_SLAVE_BOND;
+                               bond_ifindex =
+                                       *(ifindex_t *)RTA_DATA(tb[IFLA_MASTER]);
                        } else
                                zif_slave_type = ZEBRA_IF_SLAVE_OTHER;
                }
@@ -1181,7 +1218,7 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
 
                        if (ifp == NULL) {
                                /* unknown interface */
-                               ifp = if_get_by_name(name, vrf_id, 0);
+                               ifp = if_get_by_name(name, vrf_id);
                        } else {
                                /* pre-configured interface, learnt now */
                                if (ifp->vrf_id != vrf_id)
@@ -1222,6 +1259,8 @@ 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);
+                       else if (IS_ZEBRA_IF_BOND_SLAVE(ifp))
+                               zebra_l2if_update_bond_slave(ifp, bond_ifindex);
                } else if (ifp->vrf_id != vrf_id) {
                        /* VRF change for an interface. */
                        if (IS_ZEBRA_DEBUG_KERNEL)
@@ -1233,7 +1272,7 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
 
                        if_handle_vrf_change(ifp, vrf_id);
                } else {
-                       int was_bridge_slave;
+                       bool was_bridge_slave, was_bond_slave;
 
                        /* Interface update. */
                        if (IS_ZEBRA_DEBUG_KERNEL)
@@ -1256,6 +1295,7 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
                        /* Update interface type - NOTE: Only slave_type can
                         * change. */
                        was_bridge_slave = IS_ZEBRA_IF_BRIDGE_SLAVE(ifp);
+                       was_bond_slave = IS_ZEBRA_IF_BOND_SLAVE(ifp);
                        zebra_if_set_ziftype(ifp, zif_type, zif_slave_type);
 
                        netlink_interface_update_hw_addr(tb, ifp);
@@ -1295,6 +1335,8 @@ 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);
+                       else if (IS_ZEBRA_IF_BOND_SLAVE(ifp) || was_bond_slave)
+                               zebra_l2if_update_bond_slave(ifp, bond_ifindex);
                }
        } else {
                /* Delete interface notification from kernel */