]> git.proxmox.com Git - mirror_frr.git/blobdiff - zebra/if_netlink.c
Merge pull request #7384 from opensourcerouting/nb-dyn-modules
[mirror_frr.git] / zebra / if_netlink.c
index 7677db7efd267848969e0dc2c34e2f54a90d09b4..90a08bbd6c4d897154f4945705be465739a57cc3 100644 (file)
@@ -70,6 +70,7 @@
 #include "zebra/if_netlink.h"
 #include "zebra/zebra_errors.h"
 #include "zebra/zebra_vxlan.h"
+#include "zebra/zebra_evpn_mh.h"
 
 extern struct zebra_privs_t zserv_privs;
 
@@ -245,6 +246,26 @@ static enum zebra_link_type netlink_to_zebra_link_type(unsigned int hwt)
        }
 }
 
+static inline void zebra_if_set_ziftype(struct interface *ifp,
+                                       zebra_iftype_t zif_type,
+                                       zebra_slave_iftype_t zif_slave_type)
+{
+       struct zebra_if *zif;
+
+       zif = (struct zebra_if *)ifp->info;
+       zif->zif_slave_type = zif_slave_type;
+
+       if (zif->zif_type != zif_type) {
+               zif->zif_type = zif_type;
+               /* If the if_type has been set to bond initialize ES info
+                * against it. XXX - note that we don't handle the case where
+                * a zif changes from bond to non-bond; it is really
+                * an unexpected/error condition.
+                */
+               zebra_evpn_if_init(zif);
+       }
+}
+
 static void netlink_determine_zebra_iftype(const char *kind,
                                           zebra_iftype_t *zif_type)
 {
@@ -513,8 +534,7 @@ static int netlink_extract_vxlan_info(struct rtattr *link_data,
 
        if (!attr[IFLA_VXLAN_LINK]) {
                if (IS_ZEBRA_DEBUG_KERNEL)
-                       zlog_debug("IFLA_VXLAN_LINK missing "
-                                  "from VXLAN IF message");
+                       zlog_debug("IFLA_VXLAN_LINK missing from VXLAN IF message");
        } else {
                ifindex_link =
                        *(ifindex_t *)RTA_DATA(attr[IFLA_VXLAN_LINK]);
@@ -558,6 +578,74 @@ static void netlink_interface_update_l2info(struct interface *ifp,
        }
 }
 
+static int netlink_bridge_vxlan_update(struct interface *ifp,
+               struct rtattr *af_spec)
+{
+       struct rtattr *aftb[IFLA_BRIDGE_MAX + 1];
+       struct bridge_vlan_info *vinfo;
+       vlanid_t access_vlan;
+
+       /* There is a 1-to-1 mapping of VLAN to VxLAN - hence
+        * only 1 access VLAN is accepted.
+        */
+       memset(aftb, 0, sizeof(aftb));
+       parse_rtattr_nested(aftb, IFLA_BRIDGE_MAX, af_spec);
+       if (!aftb[IFLA_BRIDGE_VLAN_INFO])
+               return 0;
+
+       vinfo = RTA_DATA(aftb[IFLA_BRIDGE_VLAN_INFO]);
+       if (!(vinfo->flags & BRIDGE_VLAN_INFO_PVID))
+               return 0;
+
+       access_vlan = (vlanid_t)vinfo->vid;
+       if (IS_ZEBRA_DEBUG_KERNEL)
+               zlog_debug("Access VLAN %u for VxLAN IF %s(%u)", access_vlan,
+                               ifp->name, ifp->ifindex);
+       zebra_l2_vxlanif_update_access_vlan(ifp, access_vlan);
+       return 0;
+}
+
+static void netlink_bridge_vlan_update(struct interface *ifp,
+               struct rtattr *af_spec)
+{
+       struct rtattr *i;
+       int rem;
+       uint16_t vid_range_start = 0;
+       struct zebra_if *zif;
+       bitfield_t old_vlan_bitmap;
+       struct bridge_vlan_info *vinfo;
+
+       zif = (struct zebra_if *)ifp->info;
+
+       /* cache the old bitmap addrs */
+       old_vlan_bitmap = zif->vlan_bitmap;
+       /* create a new bitmap space for re-eval */
+       bf_init(zif->vlan_bitmap, IF_VLAN_BITMAP_MAX);
+
+       for (i = RTA_DATA(af_spec), rem = RTA_PAYLOAD(af_spec);
+                       RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
+
+               if (i->rta_type != IFLA_BRIDGE_VLAN_INFO)
+                       continue;
+
+               vinfo = RTA_DATA(i);
+
+               if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) {
+                       vid_range_start = vinfo->vid;
+                       continue;
+               }
+
+               if (!(vinfo->flags & BRIDGE_VLAN_INFO_RANGE_END))
+                       vid_range_start = vinfo->vid;
+
+               zebra_vlan_bitmap_compute(ifp, vid_range_start, vinfo->vid);
+       }
+
+       zebra_vlan_mbr_re_eval(ifp, old_vlan_bitmap);
+
+       bf_free(old_vlan_bitmap);
+}
+
 static int netlink_bridge_interface(struct nlmsghdr *h, int len, ns_id_t ns_id,
                                    int startup)
 {
@@ -565,12 +653,8 @@ static int netlink_bridge_interface(struct nlmsghdr *h, int len, ns_id_t ns_id,
        struct ifinfomsg *ifi;
        struct rtattr *tb[IFLA_MAX + 1];
        struct interface *ifp;
-       struct rtattr *aftb[IFLA_BRIDGE_MAX + 1];
-       struct {
-               uint16_t flags;
-               uint16_t vid;
-       } * vinfo;
-       vlanid_t access_vlan;
+       struct zebra_if *zif;
+       struct rtattr *af_spec;
 
        /* Fetch name and ifindex */
        ifi = NLMSG_DATA(h);
@@ -588,30 +672,22 @@ static int netlink_bridge_interface(struct nlmsghdr *h, int len, ns_id_t ns_id,
                           ifi->ifi_index);
                return 0;
        }
-       if (!IS_ZEBRA_IF_VXLAN(ifp))
-               return 0;
 
        /* We are only interested in the access VLAN i.e., AF_SPEC */
-       if (!tb[IFLA_AF_SPEC])
-               return 0;
+       af_spec = tb[IFLA_AF_SPEC];
+       if (!af_spec)
+               return 0;
 
-       /* There is a 1-to-1 mapping of VLAN to VxLAN - hence
-        * only 1 access VLAN is accepted.
-        */
-       memset(aftb, 0, sizeof(aftb));
-       parse_rtattr_nested(aftb, IFLA_BRIDGE_MAX, tb[IFLA_AF_SPEC]);
-       if (!aftb[IFLA_BRIDGE_VLAN_INFO])
-               return 0;
+       if (IS_ZEBRA_IF_VXLAN(ifp))
+               return netlink_bridge_vxlan_update(ifp, af_spec);
 
-       vinfo = RTA_DATA(aftb[IFLA_BRIDGE_VLAN_INFO]);
-       if (!(vinfo->flags & BRIDGE_VLAN_INFO_PVID))
-               return 0;
+       /* build vlan bitmap associated with this interface if that
+        * device type is interested in the vlans
+        */
+       zif = (struct zebra_if *)ifp->info;
+       if (bf_is_inited(zif->vlan_bitmap))
+               netlink_bridge_vlan_update(ifp, af_spec);
 
-       access_vlan = (vlanid_t)vinfo->vid;
-       if (IS_ZEBRA_DEBUG_KERNEL)
-               zlog_debug("Access VLAN %u for VxLAN IF %s(%u)", access_vlan,
-                          name, ifi->ifi_index);
-       zebra_l2_vxlanif_update_access_vlan(ifp, access_vlan);
        return 0;
 }
 
@@ -733,9 +809,11 @@ static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup)
         * back references on the slave interfaces is painful if not done
         * this way, i.e. by creating by ifindex.
         */
-       ifp = if_get_by_ifindex(ifi->ifi_index, vrf_id, name);
+       ifp = if_get_by_ifindex(ifi->ifi_index, vrf_id);
        set_ifindex(ifp, ifi->ifi_index, zns); /* add it to ns struct */
 
+       if_set_name(ifp, name);
+
        ifp->flags = ifi->ifi_flags & 0x0000fffff;
        ifp->mtu6 = ifp->mtu = *(uint32_t *)RTA_DATA(tb[IFLA_MTU]);
        ifp->metric = 0;
@@ -798,7 +876,7 @@ static int netlink_request_intf_addr(struct nlsock *netlink_cmd, int family,
 
        /* Include filter, if specified. */
        if (filter_mask)
-               addattr32(&req.n, sizeof(req), IFLA_EXT_MASK, filter_mask);
+               nl_attr_put32(&req.n, sizeof(req), IFLA_EXT_MASK, filter_mask);
 
        return netlink_request(netlink_cmd, &req);
 }
@@ -903,15 +981,16 @@ int kernel_interface_set_master(struct interface *master,
 
        req.ifa.ifi_index = slave->ifindex;
 
-       addattr_l(&req.n, sizeof(req), IFLA_MASTER, &master->ifindex, 4);
-       addattr_l(&req.n, sizeof(req), IFLA_LINK, &slave->ifindex, 4);
+       nl_attr_put32(&req.n, sizeof(req), IFLA_MASTER, master->ifindex);
+       nl_attr_put32(&req.n, sizeof(req), IFLA_LINK, slave->ifindex);
 
        return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns,
                            0);
 }
 
 /* Interface address modification. */
-static int netlink_address_ctx(const struct zebra_dplane_ctx *ctx)
+static ssize_t netlink_address_msg_encoder(struct zebra_dplane_ctx *ctx,
+                                          void *buf, size_t buflen)
 {
        int bytelen;
        const struct prefix *p;
@@ -921,64 +1000,72 @@ static int netlink_address_ctx(const struct zebra_dplane_ctx *ctx)
        struct {
                struct nlmsghdr n;
                struct ifaddrmsg ifa;
-               char buf[NL_PKT_BUF_SIZE];
-       } req;
+               char buf[0];
+       } *req = buf;
+
+       if (buflen < sizeof(*req))
+               return 0;
 
        p = dplane_ctx_get_intf_addr(ctx);
-       memset(&req, 0, sizeof(req) - NL_PKT_BUF_SIZE);
+       memset(req, 0, sizeof(*req));
 
        bytelen = (p->family == AF_INET ? 4 : 16);
 
-       req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
-       req.n.nlmsg_flags = NLM_F_REQUEST;
+       req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
+       req->n.nlmsg_flags = NLM_F_REQUEST;
 
        if (dplane_ctx_get_op(ctx) == DPLANE_OP_ADDR_INSTALL)
                cmd = RTM_NEWADDR;
        else
                cmd = RTM_DELADDR;
 
-       req.n.nlmsg_type = cmd;
-       req.ifa.ifa_family = p->family;
+       req->n.nlmsg_type = cmd;
+       req->ifa.ifa_family = p->family;
 
-       req.ifa.ifa_index = dplane_ctx_get_ifindex(ctx);
+       req->ifa.ifa_index = dplane_ctx_get_ifindex(ctx);
 
-       addattr_l(&req.n, sizeof(req), IFA_LOCAL, &p->u.prefix, bytelen);
+       if (!nl_attr_put(&req->n, buflen, IFA_LOCAL, &p->u.prefix, bytelen))
+               return 0;
 
        if (p->family == AF_INET) {
                if (dplane_ctx_intf_is_connected(ctx)) {
                        p = dplane_ctx_get_intf_dest(ctx);
-                       addattr_l(&req.n, sizeof(req), IFA_ADDRESS,
-                                 &p->u.prefix, bytelen);
+                       if (!nl_attr_put(&req->n, buflen, IFA_ADDRESS,
+                                        &p->u.prefix, bytelen))
+                               return 0;
                } else if (cmd == RTM_NEWADDR) {
                        struct in_addr broad = {
                                .s_addr = ipv4_broadcast_addr(p->u.prefix4.s_addr,
                                                        p->prefixlen)
                        };
-                       addattr_l(&req.n, sizeof(req), IFA_BROADCAST,
-                                 &broad, bytelen);
+                       if (!nl_attr_put(&req->n, buflen, IFA_BROADCAST, &broad,
+                                        bytelen))
+                               return 0;
                }
        }
 
        /* p is now either address or destination/bcast addr */
-       req.ifa.ifa_prefixlen = p->prefixlen;
+       req->ifa.ifa_prefixlen = p->prefixlen;
 
        if (dplane_ctx_intf_is_secondary(ctx))
-               SET_FLAG(req.ifa.ifa_flags, IFA_F_SECONDARY);
+               SET_FLAG(req->ifa.ifa_flags, IFA_F_SECONDARY);
 
        if (dplane_ctx_intf_has_label(ctx)) {
                label = dplane_ctx_get_intf_label(ctx);
-               addattr_l(&req.n, sizeof(req), IFA_LABEL, label,
-                         strlen(label) + 1);
+               if (!nl_attr_put(&req->n, buflen, IFA_LABEL, label,
+                                strlen(label) + 1))
+                       return 0;
        }
 
-       return netlink_talk_info(netlink_talk_filter, &req.n,
-                                dplane_ctx_get_ns(ctx), 0);
+       return NLMSG_ALIGN(req->n.nlmsg_len);
 }
 
-enum zebra_dplane_result kernel_address_update_ctx(struct zebra_dplane_ctx *ctx)
+enum netlink_msg_status
+netlink_put_address_update_msg(struct nl_batch *bth,
+                              struct zebra_dplane_ctx *ctx)
 {
-       return (netlink_address_ctx(ctx) == 0 ?
-               ZEBRA_DPLANE_REQUEST_SUCCESS : ZEBRA_DPLANE_REQUEST_FAILURE);
+       return netlink_batch_add_msg(bth, ctx, netlink_address_msg_encoder,
+                                    false);
 }
 
 int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup)
@@ -1307,8 +1394,7 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
                        /* Add interface notification from kernel */
                        if (IS_ZEBRA_DEBUG_KERNEL)
                                zlog_debug(
-                                       "RTM_NEWLINK ADD for %s(%u) vrf_id %u type %d "
-                                       "sl_type %d master %u flags 0x%x",
+                                       "RTM_NEWLINK ADD for %s(%u) vrf_id %u type %d sl_type %d master %u flags 0x%x",
                                        name, ifi->ifi_index, vrf_id, zif_type,
                                        zif_slave_type, bridge_ifindex,
                                        ifi->ifi_flags);
@@ -1364,8 +1450,7 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
                        /* VRF change for an interface. */
                        if (IS_ZEBRA_DEBUG_KERNEL)
                                zlog_debug(
-                                       "RTM_NEWLINK vrf-change for %s(%u) "
-                                       "vrf_id %u -> %u flags 0x%x",
+                                       "RTM_NEWLINK vrf-change for %s(%u) vrf_id %u -> %u flags 0x%x",
                                        name, ifp->ifindex, ifp->vrf_id, vrf_id,
                                        ifi->ifi_flags);
 
@@ -1376,8 +1461,7 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
                        /* Interface update. */
                        if (IS_ZEBRA_DEBUG_KERNEL)
                                zlog_debug(
-                                       "RTM_NEWLINK update for %s(%u) "
-                                       "sl_type %d master %u flags 0x%x",
+                                       "RTM_NEWLINK update for %s(%u) sl_type %d master %u flags 0x%x",
                                        name, ifp->ifindex, zif_slave_type,
                                        bridge_ifindex, ifi->ifi_flags);
 
@@ -1520,8 +1604,8 @@ int netlink_protodown(struct interface *ifp, bool down)
 
        req.ifa.ifi_index = ifp->ifindex;
 
-       addattr_l(&req.n, sizeof(req), IFLA_PROTO_DOWN, &down, sizeof(down));
-       addattr_l(&req.n, sizeof(req), IFLA_LINK, &ifp->ifindex, 4);
+       nl_attr_put(&req.n, sizeof(req), IFLA_PROTO_DOWN, &down, sizeof(down));
+       nl_attr_put32(&req.n, sizeof(req), IFLA_LINK, ifp->ifindex);
 
        return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns,
                            0);