]> 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 a15f93245121979782247c5742c22fe3bc43ec9f..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)
 {
@@ -557,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)
 {
@@ -564,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);
@@ -587,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;
 }
 
@@ -732,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;
@@ -910,7 +989,8 @@ int kernel_interface_set_master(struct interface *master,
 }
 
 /* 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;
@@ -920,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);
 
-       nl_attr_put(&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);
-                       nl_attr_put(&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)
                        };
-                       nl_attr_put(&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);
-               nl_attr_put(&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)