#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;
}
}
+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)
{
}
}
+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)
{
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);
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;
}
* 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;
}
/* 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;
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)