summaryrefslogtreecommitdiff
path: root/zebra/rt_netlink.c
diff options
context:
space:
mode:
Diffstat (limited to 'zebra/rt_netlink.c')
-rw-r--r--zebra/rt_netlink.c332
1 files changed, 182 insertions, 150 deletions
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index 95ac68fb90..91a3024038 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -92,6 +92,41 @@ void rt_netlink_init(void)
inet_pton(AF_INET, ipv4_ll_buf, &ipv4_ll);
}
+/*
+ * Mapping from dataplane neighbor flags to netlink flags
+ */
+static uint8_t neigh_flags_to_netlink(uint8_t dplane_flags)
+{
+ uint8_t flags = 0;
+
+ if (dplane_flags & DPLANE_NTF_EXT_LEARNED)
+ flags |= NTF_EXT_LEARNED;
+ if (dplane_flags & DPLANE_NTF_ROUTER)
+ flags |= NTF_ROUTER;
+
+ return flags;
+}
+
+/*
+ * Mapping from dataplane neighbor state to netlink state
+ */
+static uint16_t neigh_state_to_netlink(uint16_t dplane_state)
+{
+ uint16_t state = 0;
+
+ if (dplane_state & DPLANE_NUD_REACHABLE)
+ state |= NUD_REACHABLE;
+ if (dplane_state & DPLANE_NUD_STALE)
+ state |= NUD_STALE;
+ if (dplane_state & DPLANE_NUD_NOARP)
+ state |= NUD_NOARP;
+ if (dplane_state & DPLANE_NUD_PROBE)
+ state |= NUD_PROBE;
+
+ return state;
+}
+
+
static inline int is_selfroute(int proto)
{
if ((proto == RTPROT_BGP) || (proto == RTPROT_OSPF)
@@ -1019,33 +1054,28 @@ static void _netlink_route_build_singlepath(const char *routedesc, int bytelen,
label_buf[0] = '\0';
assert(nexthop);
- for (const struct nexthop *nh = nexthop; nh; nh = nh->rparent) {
- char label_buf1[20];
+ char label_buf1[20];
- nh_label = nh->nh_label;
- if (!nh_label || !nh_label->num_labels)
- continue;
+ nh_label = nexthop->nh_label;
- for (int i = 0; i < nh_label->num_labels; i++) {
- if (nh_label->label[i] == MPLS_LABEL_IMPLICIT_NULL)
- continue;
+ for (int i = 0; nh_label && i < nh_label->num_labels; i++) {
+ if (nh_label->label[i] == MPLS_LABEL_IMPLICIT_NULL)
+ continue;
- if (IS_ZEBRA_DEBUG_KERNEL) {
- if (!num_labels)
- sprintf(label_buf, "label %u",
- nh_label->label[i]);
- else {
- sprintf(label_buf1, "/%u",
- nh_label->label[i]);
- strlcat(label_buf, label_buf1,
- sizeof(label_buf));
- }
+ if (IS_ZEBRA_DEBUG_KERNEL) {
+ if (!num_labels)
+ sprintf(label_buf, "label %u",
+ nh_label->label[i]);
+ else {
+ sprintf(label_buf1, "/%u", nh_label->label[i]);
+ strlcat(label_buf, label_buf1,
+ sizeof(label_buf));
}
-
- out_lse[num_labels] =
- mpls_lse_encode(nh_label->label[i], 0, 0, 0);
- num_labels++;
}
+
+ out_lse[num_labels] =
+ mpls_lse_encode(nh_label->label[i], 0, 0, 0);
+ num_labels++;
}
if (num_labels) {
@@ -1210,33 +1240,28 @@ static void _netlink_route_build_multipath(const char *routedesc, int bytelen,
label_buf[0] = '\0';
assert(nexthop);
- for (const struct nexthop *nh = nexthop; nh; nh = nh->rparent) {
- char label_buf1[20];
+ char label_buf1[20];
- nh_label = nh->nh_label;
- if (!nh_label || !nh_label->num_labels)
- continue;
+ nh_label = nexthop->nh_label;
- for (int i = 0; i < nh_label->num_labels; i++) {
- if (nh_label->label[i] == MPLS_LABEL_IMPLICIT_NULL)
- continue;
+ for (int i = 0; nh_label && i < nh_label->num_labels; i++) {
+ if (nh_label->label[i] == MPLS_LABEL_IMPLICIT_NULL)
+ continue;
- if (IS_ZEBRA_DEBUG_KERNEL) {
- if (!num_labels)
- sprintf(label_buf, "label %u",
- nh_label->label[i]);
- else {
- sprintf(label_buf1, "/%u",
- nh_label->label[i]);
- strlcat(label_buf, label_buf1,
- sizeof(label_buf));
- }
+ if (IS_ZEBRA_DEBUG_KERNEL) {
+ if (!num_labels)
+ sprintf(label_buf, "label %u",
+ nh_label->label[i]);
+ else {
+ sprintf(label_buf1, "/%u", nh_label->label[i]);
+ strlcat(label_buf, label_buf1,
+ sizeof(label_buf));
}
-
- out_lse[num_labels] =
- mpls_lse_encode(nh_label->label[i], 0, 0, 0);
- num_labels++;
}
+
+ out_lse[num_labels] =
+ mpls_lse_encode(nh_label->label[i], 0, 0, 0);
+ num_labels++;
}
if (num_labels) {
@@ -1902,19 +1927,17 @@ int kernel_neigh_update(int add, int ifindex, uint32_t addr, char *lla,
* Add remote VTEP to the flood list for this VxLAN interface (VNI). This
* is done by adding an FDB entry with a MAC of 00:00:00:00:00:00.
*/
-static int netlink_vxlan_flood_list_update(struct interface *ifp,
- struct in_addr *vtep_ip, int cmd)
+static int netlink_vxlan_flood_update_ctx(const struct zebra_dplane_ctx *ctx,
+ int cmd)
{
- struct zebra_ns *zns;
struct {
struct nlmsghdr n;
struct ndmsg ndm;
char buf[256];
} req;
uint8_t dst_mac[6] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
- struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(ifp->vrf_id);
+ const struct ipaddr *addr;
- zns = zvrf->zns;
memset(&req, 0, sizeof(req));
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg));
@@ -1928,39 +1951,14 @@ static int netlink_vxlan_flood_list_update(struct interface *ifp,
addattr_l(&req.n, sizeof(req), NDA_LLADDR, &dst_mac, 6);
- req.ndm.ndm_ifindex = ifp->ifindex;
- addattr_l(&req.n, sizeof(req), NDA_DST, &vtep_ip->s_addr, 4);
+ req.ndm.ndm_ifindex = dplane_ctx_get_ifindex(ctx);
- return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns,
- 0);
-}
-
-/*
- * Add remote VTEP for this VxLAN interface (VNI). In Linux, this involves
- * adding
- * a "flood" MAC FDB entry.
- */
-int kernel_add_vtep(vni_t vni, struct interface *ifp, struct in_addr *vtep_ip)
-{
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("Install %s into flood list for VNI %u intf %s(%u)",
- inet_ntoa(*vtep_ip), vni, ifp->name, ifp->ifindex);
+ addr = dplane_ctx_neigh_get_ipaddr(ctx);
- return netlink_vxlan_flood_list_update(ifp, vtep_ip, RTM_NEWNEIGH);
-}
+ addattr_l(&req.n, sizeof(req), NDA_DST, &(addr->ipaddr_v4), 4);
-/*
- * Remove remote VTEP for this VxLAN interface (VNI). In Linux, this involves
- * deleting the "flood" MAC FDB entry.
- */
-int kernel_del_vtep(vni_t vni, struct interface *ifp, struct in_addr *vtep_ip)
-{
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(
- "Uninstall %s from flood list for VNI %u intf %s(%u)",
- inet_ntoa(*vtep_ip), vni, ifp->name, ifp->ifindex);
-
- return netlink_vxlan_flood_list_update(ifp, vtep_ip, RTM_DELNEIGH);
+ return netlink_talk_info(netlink_talk_filter, &req.n,
+ dplane_ctx_get_ns(ctx), 0);
}
#ifndef NDA_RTA
@@ -2292,34 +2290,29 @@ int netlink_macfdb_read_specific_mac(struct zebra_ns *zns,
return ret;
}
-static int netlink_macfdb_update(struct interface *ifp, vlanid_t vid,
- struct ethaddr *mac, struct in_addr vtep_ip,
- int cmd, bool sticky)
+
+/*
+ * Netlink-specific handler for MAC updates using dataplane context object.
+ */
+static enum zebra_dplane_result
+netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx)
{
- struct zebra_ns *zns;
struct {
struct nlmsghdr n;
struct ndmsg ndm;
char buf[256];
} req;
+ int ret;
int dst_alen;
- struct zebra_if *zif;
- struct interface *br_if;
- struct zebra_if *br_zif;
- char buf[ETHER_ADDR_STRLEN];
int vid_present = 0;
- char vid_buf[20];
- char dst_buf[30];
- struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(ifp->vrf_id);
+ int cmd;
+ struct in_addr vtep_ip;
+ vlanid_t vid;
- zns = zvrf->zns;
- zif = ifp->info;
- if ((br_if = zif->brslave_info.br_if) == NULL) {
- zlog_debug("MAC %s on IF %s(%u) - no mapping to bridge",
- (cmd == RTM_NEWNEIGH) ? "add" : "del", ifp->name,
- ifp->ifindex);
- return -1;
- }
+ if (dplane_ctx_get_op(ctx) == DPLANE_OP_MAC_INSTALL)
+ cmd = RTM_NEWNEIGH;
+ else
+ cmd = RTM_DELNEIGH;
memset(&req, 0, sizeof(req));
@@ -2332,34 +2325,58 @@ static int netlink_macfdb_update(struct interface *ifp, vlanid_t vid,
req.ndm.ndm_flags |= NTF_SELF | NTF_MASTER;
req.ndm.ndm_state = NUD_REACHABLE;
- if (sticky)
+ if (dplane_ctx_mac_is_sticky(ctx))
req.ndm.ndm_state |= NUD_NOARP;
else
req.ndm.ndm_flags |= NTF_EXT_LEARNED;
- addattr_l(&req.n, sizeof(req), NDA_LLADDR, mac, 6);
- req.ndm.ndm_ifindex = ifp->ifindex;
+ addattr_l(&req.n, sizeof(req), NDA_LLADDR,
+ dplane_ctx_mac_get_addr(ctx), 6);
+ req.ndm.ndm_ifindex = dplane_ctx_get_ifindex(ctx);
+
dst_alen = 4; // TODO: hardcoded
+ vtep_ip = *(dplane_ctx_mac_get_vtep_ip(ctx));
addattr_l(&req.n, sizeof(req), NDA_DST, &vtep_ip, dst_alen);
- sprintf(dst_buf, " dst %s", inet_ntoa(vtep_ip));
- br_zif = (struct zebra_if *)br_if->info;
- if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif) && vid > 0) {
+
+ vid = dplane_ctx_mac_get_vlan(ctx);
+
+ if (vid > 0) {
addattr16(&req.n, sizeof(req), NDA_VLAN, vid);
vid_present = 1;
- sprintf(vid_buf, " VLAN %u", vid);
}
- addattr32(&req.n, sizeof(req), NDA_MASTER, br_if->ifindex);
+ addattr32(&req.n, sizeof(req), NDA_MASTER,
+ dplane_ctx_mac_get_br_ifindex(ctx));
+
+ if (IS_ZEBRA_DEBUG_KERNEL) {
+ char ipbuf[PREFIX_STRLEN];
+ char buf[ETHER_ADDR_STRLEN];
+ char dst_buf[PREFIX_STRLEN + 10];
+ char vid_buf[20];
+
+ if (vid_present)
+ snprintf(vid_buf, sizeof(vid_buf), " VLAN %u", vid);
+ else
+ vid_buf[0] = '\0';
+
+ inet_ntop(AF_INET, &vtep_ip, ipbuf, sizeof(ipbuf));
+ snprintf(dst_buf, sizeof(dst_buf), " dst %s", ipbuf);
+ prefix_mac2str(dplane_ctx_mac_get_addr(ctx), buf, sizeof(buf));
- if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("Tx %s family %s IF %s(%u)%s %sMAC %s%s",
nl_msg_type_to_str(cmd),
- nl_family_to_str(req.ndm.ndm_family), ifp->name,
- ifp->ifindex, vid_present ? vid_buf : "",
- sticky ? "sticky " : "",
- prefix_mac2str(mac, buf, sizeof(buf)), dst_buf);
+ nl_family_to_str(req.ndm.ndm_family),
+ dplane_ctx_get_ifname(ctx),
+ dplane_ctx_get_ifindex(ctx), vid_buf,
+ dplane_ctx_mac_is_sticky(ctx) ? "sticky " : "",
+ buf, dst_buf);
+ }
- return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns,
- 0);
+ ret = netlink_talk_info(netlink_talk_filter, &req.n,
+ dplane_ctx_get_ns(ctx), 0);
+ if (ret == 0)
+ return ZEBRA_DPLANE_REQUEST_SUCCESS;
+ else
+ return ZEBRA_DPLANE_REQUEST_FAILURE;
}
/*
@@ -2725,9 +2742,11 @@ int netlink_neigh_change(struct nlmsghdr *h, ns_id_t ns_id)
return 0;
}
-static int netlink_neigh_update2(struct interface *ifp, struct ipaddr *ip,
- struct ethaddr *mac, uint8_t flags,
- uint16_t state, int cmd)
+/*
+ * Utility neighbor-update function, using info from dplane context.
+ */
+static int netlink_neigh_update_ctx(const struct zebra_dplane_ctx *ctx,
+ int cmd)
{
struct {
struct nlmsghdr n;
@@ -2735,15 +2754,23 @@ static int netlink_neigh_update2(struct interface *ifp, struct ipaddr *ip,
char buf[256];
} req;
int ipa_len;
-
- struct zebra_ns *zns;
char buf[INET6_ADDRSTRLEN];
char buf2[ETHER_ADDR_STRLEN];
- struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(ifp->vrf_id);
+ const struct ipaddr *ip;
+ const struct ethaddr *mac;
+ uint8_t flags;
+ uint16_t state;
- zns = zvrf->zns;
memset(&req, 0, sizeof(req));
+ ip = dplane_ctx_neigh_get_ipaddr(ctx);
+ mac = dplane_ctx_neigh_get_mac(ctx);
+ if (is_zero_mac(mac))
+ mac = NULL;
+
+ flags = neigh_flags_to_netlink(dplane_ctx_neigh_get_flags(ctx));
+ state = neigh_state_to_netlink(dplane_ctx_neigh_get_state(ctx));
+
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg));
req.n.nlmsg_flags = NLM_F_REQUEST;
if (cmd == RTM_NEWNEIGH)
@@ -2751,7 +2778,7 @@ static int netlink_neigh_update2(struct interface *ifp, struct ipaddr *ip,
req.n.nlmsg_type = cmd; // RTM_NEWNEIGH or RTM_DELNEIGH
req.ndm.ndm_family = IS_IPADDR_V4(ip) ? AF_INET : AF_INET6;
req.ndm.ndm_state = state;
- req.ndm.ndm_ifindex = ifp->ifindex;
+ req.ndm.ndm_ifindex = dplane_ctx_get_ifindex(ctx);
req.ndm.ndm_type = RTN_UNICAST;
req.ndm.ndm_flags = flags;
@@ -2763,45 +2790,50 @@ static int netlink_neigh_update2(struct interface *ifp, struct ipaddr *ip,
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("Tx %s family %s IF %s(%u) Neigh %s MAC %s flags 0x%x state 0x%x",
nl_msg_type_to_str(cmd),
- nl_family_to_str(req.ndm.ndm_family), ifp->name,
- ifp->ifindex, ipaddr2str(ip, buf, sizeof(buf)),
+ nl_family_to_str(req.ndm.ndm_family),
+ dplane_ctx_get_ifname(ctx),
+ dplane_ctx_get_ifindex(ctx),
+ ipaddr2str(ip, buf, sizeof(buf)),
mac ? prefix_mac2str(mac, buf2, sizeof(buf2))
- : "null", flags, state);
+ : "null",
+ flags, state);
- return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns,
- 0);
+ return netlink_talk_info(netlink_talk_filter, &req.n,
+ dplane_ctx_get_ns(ctx), 0);
}
-int kernel_add_mac(struct interface *ifp, vlanid_t vid, struct ethaddr *mac,
- struct in_addr vtep_ip, bool sticky)
+/*
+ * Update MAC, using dataplane context object.
+ */
+enum zebra_dplane_result kernel_mac_update_ctx(struct zebra_dplane_ctx *ctx)
{
- return netlink_macfdb_update(ifp, vid, mac, vtep_ip, RTM_NEWNEIGH,
- sticky);
+ return netlink_macfdb_update_ctx(ctx);
}
-int kernel_del_mac(struct interface *ifp, vlanid_t vid, struct ethaddr *mac,
- struct in_addr vtep_ip)
+enum zebra_dplane_result kernel_neigh_update_ctx(struct zebra_dplane_ctx *ctx)
{
- return netlink_macfdb_update(ifp, vid, mac, vtep_ip, RTM_DELNEIGH, 0);
-}
+ int ret = -1;
-int kernel_add_neigh(struct interface *ifp, struct ipaddr *ip,
- struct ethaddr *mac, uint8_t flags)
-{
- return netlink_neigh_update2(ifp, ip, mac, flags,
- NUD_NOARP, RTM_NEWNEIGH);
-}
-
-int kernel_del_neigh(struct interface *ifp, struct ipaddr *ip)
-{
- return netlink_neigh_update2(ifp, ip, NULL, 0, 0, RTM_DELNEIGH);
-}
+ switch (dplane_ctx_get_op(ctx)) {
+ case DPLANE_OP_NEIGH_INSTALL:
+ case DPLANE_OP_NEIGH_UPDATE:
+ ret = netlink_neigh_update_ctx(ctx, RTM_NEWNEIGH);
+ break;
+ case DPLANE_OP_NEIGH_DELETE:
+ ret = netlink_neigh_update_ctx(ctx, RTM_DELNEIGH);
+ break;
+ case DPLANE_OP_VTEP_ADD:
+ ret = netlink_vxlan_flood_update_ctx(ctx, RTM_NEWNEIGH);
+ break;
+ case DPLANE_OP_VTEP_DELETE:
+ ret = netlink_vxlan_flood_update_ctx(ctx, RTM_DELNEIGH);
+ break;
+ default:
+ break;
+ }
-int kernel_upd_neigh(struct interface *ifp, struct ipaddr *ip,
- struct ethaddr *mac, uint8_t flags, uint16_t state)
-{
- return netlink_neigh_update2(ifp, ip, mac, flags,
- state, RTM_NEWNEIGH);
+ return (ret == 0 ?
+ ZEBRA_DPLANE_REQUEST_SUCCESS : ZEBRA_DPLANE_REQUEST_FAILURE);
}
/*