summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--zebra/if_netlink.c15
-rw-r--r--zebra/if_netlink.h7
-rw-r--r--zebra/kernel_netlink.c195
-rw-r--r--zebra/kernel_netlink.h9
-rw-r--r--zebra/rt_netlink.c36
-rw-r--r--zebra/rt_netlink.h6
-rw-r--r--zebra/rule_netlink.c3
-rw-r--r--zebra/rule_netlink.h3
8 files changed, 160 insertions, 114 deletions
diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c
index 6c32407f7b..f153cc3510 100644
--- a/zebra/if_netlink.c
+++ b/zebra/if_netlink.c
@@ -557,10 +557,11 @@ static int netlink_bridge_interface(struct nlmsghdr *h, int len, ns_id_t ns_id,
return 0;
}
-/* Called from interface_lookup_netlink(). This function is only used
- during bootstrap. */
-static int netlink_interface(struct sockaddr_nl *snl, struct nlmsghdr *h,
- ns_id_t ns_id, int startup)
+/*
+ * Called from interface_lookup_netlink(). This function is only used
+ * during bootstrap.
+ */
+static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup)
{
int len;
struct ifinfomsg *ifi;
@@ -872,8 +873,7 @@ int kernel_address_delete_ipv6(struct interface *ifp, struct connected *ifc)
return netlink_address(RTM_DELADDR, AF_INET6, ifp, ifc);
}
-int netlink_interface_addr(struct sockaddr_nl *snl, struct nlmsghdr *h,
- ns_id_t ns_id, int startup)
+int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup)
{
int len;
struct ifaddrmsg *ifa;
@@ -1076,8 +1076,7 @@ static void if_netlink_check_ifp_instance_consistency(uint16_t cmd,
*/
}
-int netlink_link_change(struct sockaddr_nl *snl, struct nlmsghdr *h,
- ns_id_t ns_id, int startup)
+int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
{
int len;
struct ifinfomsg *ifi;
diff --git a/zebra/if_netlink.h b/zebra/if_netlink.h
index 769c68a87e..65a266a519 100644
--- a/zebra/if_netlink.h
+++ b/zebra/if_netlink.h
@@ -23,10 +23,9 @@
#ifdef HAVE_NETLINK
-extern int netlink_interface_addr(struct sockaddr_nl *snl, struct nlmsghdr *h,
- ns_id_t ns_id, int startup);
-extern int netlink_link_change(struct sockaddr_nl *snl, struct nlmsghdr *h,
- ns_id_t ns_id, int startup);
+extern int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id,
+ int startup);
+extern int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup);
extern int interface_lookup_netlink(struct zebra_ns *zns);
#endif /* HAVE_NETLINK */
diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c
index ac5baba1cd..0e79b82533 100644
--- a/zebra/kernel_netlink.c
+++ b/zebra/kernel_netlink.c
@@ -129,11 +129,22 @@ extern uint32_t nl_rcvbufsize;
extern struct zebra_privs_t zserv_privs;
-int netlink_talk_filter(struct sockaddr_nl *snl, struct nlmsghdr *h,
- ns_id_t ns_id, int startup)
+int netlink_talk_filter(struct nlmsghdr *h, ns_id_t ns_id, int startup)
{
- zlog_warn("netlink_talk: ignoring message type 0x%04x NS %u",
- h->nlmsg_type, ns_id);
+ /*
+ * This is an error condition that must be handled during
+ * development.
+ *
+ * The netlink_talk_filter function is used for communication
+ * down the netlink_cmd pipe and we are expecting
+ * an ack being received. So if we get here
+ * then we did not receive the ack and instead
+ * received some other message in an unexpected
+ * way.
+ */
+ zlog_err("%s: ignoring message type 0x%04x(%s) NS %u",
+ __PRETTY_FUNCTION__, h->nlmsg_type,
+ nl_msg_type_to_str(h->nlmsg_type), ns_id);
return 0;
}
@@ -233,41 +244,50 @@ static int netlink_socket(struct nlsock *nl, unsigned long groups,
return ret;
}
-static int netlink_information_fetch(struct sockaddr_nl *snl,
- struct nlmsghdr *h, ns_id_t ns_id,
+static int netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id,
int startup)
{
- /* JF: Ignore messages that aren't from the kernel */
- if (snl->nl_pid != 0) {
- zlog_err("Ignoring message from pid %u", snl->nl_pid);
- return 0;
- }
-
+ /*
+ * When we handle new message types here
+ * because we are starting to install them
+ * then lets check the netlink_install_filter
+ * and see if we should add the corresponding
+ * allow through entry there.
+ * Probably not needed to do but please
+ * think about it.
+ */
switch (h->nlmsg_type) {
case RTM_NEWROUTE:
- return netlink_route_change(snl, h, ns_id, startup);
+ return netlink_route_change(h, ns_id, startup);
case RTM_DELROUTE:
- return netlink_route_change(snl, h, ns_id, startup);
+ return netlink_route_change(h, ns_id, startup);
case RTM_NEWLINK:
- return netlink_link_change(snl, h, ns_id, startup);
+ return netlink_link_change(h, ns_id, startup);
case RTM_DELLINK:
- return netlink_link_change(snl, h, ns_id, startup);
+ return netlink_link_change(h, ns_id, startup);
case RTM_NEWADDR:
- return netlink_interface_addr(snl, h, ns_id, startup);
+ return netlink_interface_addr(h, ns_id, startup);
case RTM_DELADDR:
- return netlink_interface_addr(snl, h, ns_id, startup);
+ return netlink_interface_addr(h, ns_id, startup);
case RTM_NEWNEIGH:
- return netlink_neigh_change(snl, h, ns_id);
+ return netlink_neigh_change(h, ns_id);
case RTM_DELNEIGH:
- return netlink_neigh_change(snl, h, ns_id);
+ return netlink_neigh_change(h, ns_id);
case RTM_NEWRULE:
- return netlink_rule_change(snl, h, ns_id, startup);
+ return netlink_rule_change(h, ns_id, startup);
case RTM_DELRULE:
- return netlink_rule_change(snl, h, ns_id, startup);
+ return netlink_rule_change(h, ns_id, startup);
default:
- if (IS_ZEBRA_DEBUG_KERNEL)
- zlog_debug("Unknown netlink nlmsg_type %d vrf %u\n",
- h->nlmsg_type, ns_id);
+ /*
+ * If we have received this message then
+ * we have made a mistake during development
+ * and we need to write some code to handle
+ * this message type or not ask for
+ * it to be sent up to us
+ */
+ zlog_err("Unknown netlink nlmsg_type %s(%d) vrf %u\n",
+ nl_msg_type_to_str(h->nlmsg_type), h->nlmsg_type,
+ ns_id);
break;
}
return 0;
@@ -284,31 +304,69 @@ static int kernel_read(struct thread *thread)
return 0;
}
-/* Filter out messages from self that occur on listener socket,
+/*
+ * Filter out messages from self that occur on listener socket,
* caused by our actions on the command socket
+ *
+ * When we add new Netlink message types we probably
+ * do not need to add them here as that we are filtering
+ * on the routes we actually care to receive( which is rarer
+ * then the normal course of operations). We are intentionally
+ * allowing some messages from ourselves through
+ * ( I'm looking at you Interface based netlink messages )
+ * so that we only had to write one way to handle incoming
+ * address add/delete changes.
*/
static void netlink_install_filter(int sock, __u32 pid)
{
+ /*
+ * BPF_JUMP instructions and where you jump to are based upon
+ * 0 as being the next statement. So count from 0. Writing
+ * this down because every time I look at this I have to
+ * re-remember it.
+ */
struct sock_filter filter[] = {
- /* 0: ldh [4] */
- BPF_STMT(BPF_LD | BPF_ABS | BPF_H,
- offsetof(struct nlmsghdr, nlmsg_type)),
- /* 1: jeq 0x18 jt 5 jf next */
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htons(RTM_NEWROUTE), 3, 0),
- /* 2: jeq 0x19 jt 5 jf next */
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htons(RTM_DELROUTE), 2, 0),
- /* 3: jeq 0x19 jt 5 jf next */
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htons(RTM_NEWNEIGH), 1, 0),
- /* 4: jeq 0x19 jt 5 jf 8 */
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htons(RTM_DELNEIGH), 0, 3),
- /* 5: ldw [12] */
+ /*
+ * Logic:
+ * if (nlmsg_pid == pid) {
+ * if (the incoming nlmsg_type ==
+ * RTM_NEWADDR | RTM_DELADDR)
+ * keep this message
+ * else
+ * skip this message
+ * } else
+ * keep this netlink message
+ */
+ /*
+ * 0: Load the nlmsg_pid into the BPF register
+ */
BPF_STMT(BPF_LD | BPF_ABS | BPF_W,
offsetof(struct nlmsghdr, nlmsg_pid)),
- /* 6: jeq XX jt 7 jf 8 */
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htonl(pid), 0, 1),
- /* 7: ret 0 (skip) */
+ /*
+ * 1: Compare to pid
+ */
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htonl(pid), 0, 4),
+ /*
+ * 2: Load the nlmsg_type into BPF register
+ */
+ BPF_STMT(BPF_LD | BPF_ABS | BPF_H,
+ offsetof(struct nlmsghdr, nlmsg_type)),
+ /*
+ * 3: Compare to RTM_NEWADDR
+ */
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htons(RTM_NEWADDR), 2, 0),
+ /*
+ * 4: Compare to RTM_DELADDR
+ */
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htons(RTM_DELADDR), 1, 0),
+ /*
+ * 5: This is the end state of we want to skip the
+ * message
+ */
BPF_STMT(BPF_RET | BPF_K, 0),
- /* 8: ret 0xffff (keep) */
+ /* 6: This is the end state of we want to keep
+ * the message
+ */
BPF_STMT(BPF_RET | BPF_K, 0xffff),
};
@@ -453,8 +511,7 @@ const char *nl_rttype_to_str(uint8_t rttype)
* startup -> Are we reading in under startup conditions? passed to
* the filter.
*/
-int netlink_parse_info(int (*filter)(struct sockaddr_nl *, struct nlmsghdr *,
- ns_id_t, int),
+int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int),
struct nlsock *nl, struct zebra_ns *zns, int count,
int startup)
{
@@ -621,24 +678,18 @@ int netlink_parse_info(int (*filter)(struct sockaddr_nl *, struct nlmsghdr *,
h->nlmsg_type, h->nlmsg_len,
h->nlmsg_seq, h->nlmsg_pid);
- /* skip unsolicited messages originating from command
- * socket
- * linux sets the originators port-id for {NEW|DEL}ADDR
- * messages,
- * so this has to be checked here. */
- if (nl != &zns->netlink_cmd
- && h->nlmsg_pid == zns->netlink_cmd.snl.nl_pid
- && (h->nlmsg_type != RTM_NEWADDR
- && h->nlmsg_type != RTM_DELADDR)) {
- if (IS_ZEBRA_DEBUG_KERNEL)
- zlog_debug(
- "netlink_parse_info: %s packet comes from %s",
- zns->netlink_cmd.name,
- nl->name);
+
+ /*
+ * Ignore messages that maybe sent from
+ * other actors besides the kernel
+ */
+ if (snl.nl_pid != 0) {
+ zlog_err("Ignoring message from pid %u",
+ snl.nl_pid);
continue;
}
- error = (*filter)(&snl, h, zns->ns_id, startup);
+ error = (*filter)(h, zns->ns_id, startup);
if (error < 0) {
zlog_err("%s filter function error", nl->name);
ret = error;
@@ -672,8 +723,7 @@ int netlink_parse_info(int (*filter)(struct sockaddr_nl *, struct nlmsghdr *,
* startup -> Are we reading in under startup conditions
* This is passed through eventually to filter.
*/
-int netlink_talk(int (*filter)(struct sockaddr_nl *, struct nlmsghdr *, ns_id_t,
- int startup),
+int netlink_talk(int (*filter)(struct nlmsghdr *, ns_id_t, int startup),
struct nlmsghdr *n, struct nlsock *nl, struct zebra_ns *zns,
int startup)
{
@@ -787,11 +837,24 @@ void kernel_init(struct zebra_ns *zns)
{
unsigned long groups;
- /* Initialize netlink sockets */
- groups = RTMGRP_LINK | RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_IFADDR
- | RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFADDR | RTMGRP_IPV4_MROUTE
- | RTMGRP_NEIGH
- | RTNLGRP_IPV4_RULE | RTNLGRP_IPV6_RULE;
+ /*
+ * Initialize netlink sockets
+ *
+ * If RTMGRP_XXX exists use that, but at some point
+ * I think the kernel developers realized that
+ * keeping track of all the different values would
+ * lead to confusion, so we need to convert the
+ * RTNLGRP_XXX to a bit position for ourself
+ */
+ groups = RTMGRP_LINK |
+ RTMGRP_IPV4_ROUTE |
+ RTMGRP_IPV4_IFADDR |
+ RTMGRP_IPV6_ROUTE |
+ RTMGRP_IPV6_IFADDR |
+ RTMGRP_IPV4_MROUTE |
+ RTMGRP_NEIGH |
+ (1 << (RTNLGRP_IPV4_RULE - 1)) |
+ (1 << (RTNLGRP_IPV6_RULE - 1));
snprintf(zns->netlink.name, sizeof(zns->netlink.name),
"netlink-listen (NS %u)", zns->ns_id);
diff --git a/zebra/kernel_netlink.h b/zebra/kernel_netlink.h
index dc075b9aff..3b4048ff69 100644
--- a/zebra/kernel_netlink.h
+++ b/zebra/kernel_netlink.h
@@ -45,14 +45,11 @@ extern const char *nl_rtproto_to_str(uint8_t rtproto);
extern const char *nl_family_to_str(uint8_t family);
extern const char *nl_rttype_to_str(uint8_t rttype);
-extern int netlink_parse_info(int (*filter)(struct sockaddr_nl *,
- struct nlmsghdr *, ns_id_t, int),
+extern int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int),
struct nlsock *nl, struct zebra_ns *zns,
int count, int startup);
-extern int netlink_talk_filter(struct sockaddr_nl *, struct nlmsghdr *, ns_id_t,
- int startup);
-extern int netlink_talk(int (*filter)(struct sockaddr_nl *, struct nlmsghdr *,
- ns_id_t, int startup),
+extern int netlink_talk_filter(struct nlmsghdr *h, ns_id_t ns, int startup);
+extern int netlink_talk(int (*filter)(struct nlmsghdr *, ns_id_t, int startup),
struct nlmsghdr *n, struct nlsock *nl,
struct zebra_ns *zns, int startup);
extern int netlink_request(struct nlsock *nl, struct nlmsghdr *n);
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index 08c81d037a..e9b3e59d0e 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -247,8 +247,7 @@ static vrf_id_t vrf_lookup_by_table(uint32_t table_id, ns_id_t ns_id)
}
/* Looking up routing table by netlink interface. */
-static int netlink_route_change_read_unicast(struct sockaddr_nl *snl,
- struct nlmsghdr *h, ns_id_t ns_id,
+static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,
int startup)
{
int len;
@@ -632,8 +631,7 @@ static int netlink_route_change_read_unicast(struct sockaddr_nl *snl,
static struct mcast_route_data *mroute = NULL;
-static int netlink_route_change_read_multicast(struct sockaddr_nl *snl,
- struct nlmsghdr *h,
+static int netlink_route_change_read_multicast(struct nlmsghdr *h,
ns_id_t ns_id, int startup)
{
int len;
@@ -722,8 +720,7 @@ static int netlink_route_change_read_multicast(struct sockaddr_nl *snl,
return 0;
}
-int netlink_route_change(struct sockaddr_nl *snl, struct nlmsghdr *h,
- ns_id_t ns_id, int startup)
+int netlink_route_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
{
int len;
struct rtmsg *rtm;
@@ -754,9 +751,9 @@ int netlink_route_change(struct sockaddr_nl *snl, struct nlmsghdr *h,
return -1;
if (rtm->rtm_type == RTN_MULTICAST)
- netlink_route_change_read_multicast(snl, h, ns_id, startup);
+ netlink_route_change_read_multicast(h, ns_id, startup);
else
- netlink_route_change_read_unicast(snl, h, ns_id, startup);
+ netlink_route_change_read_unicast(h, ns_id, startup);
return 0;
}
@@ -1815,8 +1812,7 @@ int kernel_del_vtep(vni_t vni, struct interface *ifp, struct in_addr *vtep_ip)
((struct rtattr *)(((char *)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg))))
#endif
-static int netlink_macfdb_change(struct sockaddr_nl *snl, struct nlmsghdr *h,
- int len, ns_id_t ns_id)
+static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
{
struct ndmsg *ndm;
struct interface *ifp;
@@ -1951,8 +1947,7 @@ static int netlink_macfdb_change(struct sockaddr_nl *snl, struct nlmsghdr *h,
return zebra_vxlan_local_mac_del(ifp, br_if, &mac, vid);
}
-static int netlink_macfdb_table(struct sockaddr_nl *snl, struct nlmsghdr *h,
- ns_id_t ns_id, int startup)
+static int netlink_macfdb_table(struct nlmsghdr *h, ns_id_t ns_id, int startup)
{
int len;
struct ndmsg *ndm;
@@ -1970,7 +1965,7 @@ static int netlink_macfdb_table(struct sockaddr_nl *snl, struct nlmsghdr *h,
if (ndm->ndm_family != AF_BRIDGE)
return 0;
- return netlink_macfdb_change(snl, h, len, ns_id);
+ return netlink_macfdb_change(h, len, ns_id);
}
/* Request for MAC FDB information from the kernel */
@@ -2126,8 +2121,7 @@ static int netlink_macfdb_update(struct interface *ifp, vlanid_t vid,
(NUD_PERMANENT | NUD_NOARP | NUD_REACHABLE | NUD_PROBE | NUD_STALE \
| NUD_DELAY)
-static int netlink_ipneigh_change(struct sockaddr_nl *snl, struct nlmsghdr *h,
- int len, ns_id_t ns_id)
+static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
{
struct ndmsg *ndm;
struct interface *ifp;
@@ -2270,8 +2264,7 @@ static int netlink_ipneigh_change(struct sockaddr_nl *snl, struct nlmsghdr *h,
return zebra_vxlan_handle_kernel_neigh_del(ifp, link_if, &ip);
}
-static int netlink_neigh_table(struct sockaddr_nl *snl, struct nlmsghdr *h,
- ns_id_t ns_id, int startup)
+static int netlink_neigh_table(struct nlmsghdr *h, ns_id_t ns_id, int startup)
{
int len;
struct ndmsg *ndm;
@@ -2289,7 +2282,7 @@ static int netlink_neigh_table(struct sockaddr_nl *snl, struct nlmsghdr *h,
if (ndm->ndm_family != AF_INET && ndm->ndm_family != AF_INET6)
return 0;
- return netlink_neigh_change(snl, h, len);
+ return netlink_neigh_change(h, len);
}
/* Request for IP neighbor information from the kernel */
@@ -2349,8 +2342,7 @@ int netlink_neigh_read_for_vlan(struct zebra_ns *zns, struct interface *vlan_if)
return ret;
}
-int netlink_neigh_change(struct sockaddr_nl *snl, struct nlmsghdr *h,
- ns_id_t ns_id)
+int netlink_neigh_change(struct nlmsghdr *h, ns_id_t ns_id)
{
int len;
struct ndmsg *ndm;
@@ -2366,13 +2358,13 @@ int netlink_neigh_change(struct sockaddr_nl *snl, struct nlmsghdr *h,
/* Is this a notification for the MAC FDB or IP neighbor table? */
ndm = NLMSG_DATA(h);
if (ndm->ndm_family == AF_BRIDGE)
- return netlink_macfdb_change(snl, h, len, ns_id);
+ return netlink_macfdb_change(h, len, ns_id);
if (ndm->ndm_type != RTN_UNICAST)
return 0;
if (ndm->ndm_family == AF_INET || ndm->ndm_family == AF_INET6)
- return netlink_ipneigh_change(snl, h, len, ns_id);
+ return netlink_ipneigh_change(h, len, ns_id);
return 0;
}
diff --git a/zebra/rt_netlink.h b/zebra/rt_netlink.h
index c8d918b1d2..c4f21d1504 100644
--- a/zebra/rt_netlink.h
+++ b/zebra/rt_netlink.h
@@ -59,12 +59,10 @@ void rt_netlink_init(void);
extern int netlink_mpls_multipath(int cmd, zebra_lsp_t *lsp);
-extern int netlink_route_change(struct sockaddr_nl *snl, struct nlmsghdr *h,
- ns_id_t ns_id, int startup);
+extern int netlink_route_change(struct nlmsghdr *h, ns_id_t ns_id, int startup);
extern int netlink_route_read(struct zebra_ns *zns);
-extern int netlink_neigh_change(struct sockaddr_nl *snl, struct nlmsghdr *h,
- ns_id_t ns_id);
+extern int netlink_neigh_change(struct nlmsghdr *h, ns_id_t ns_id);
extern int netlink_macfdb_read(struct zebra_ns *zns);
extern int netlink_macfdb_read_for_bridge(struct zebra_ns *zns,
struct interface *ifp,
diff --git a/zebra/rule_netlink.c b/zebra/rule_netlink.c
index 310f0952fa..5f73545855 100644
--- a/zebra/rule_netlink.c
+++ b/zebra/rule_netlink.c
@@ -166,8 +166,7 @@ void kernel_del_pbr_rule(struct zebra_pbr_rule *rule)
* notification of interest. The expectation is that if this corresponds
* to a PBR rule added by FRR, it will be readded.
*/
-int netlink_rule_change(struct sockaddr_nl *snl, struct nlmsghdr *h,
- ns_id_t ns_id, int startup)
+int netlink_rule_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
{
struct zebra_ns *zns;
struct fib_rule_hdr *frh;
diff --git a/zebra/rule_netlink.h b/zebra/rule_netlink.h
index 3a9b51309e..4547a1bb3b 100644
--- a/zebra/rule_netlink.h
+++ b/zebra/rule_netlink.h
@@ -29,8 +29,7 @@
/*
* Handle netlink notification informing a rule add or delete.
*/
-extern int netlink_rule_change(struct sockaddr_nl *snl, struct nlmsghdr *h,
- ns_id_t ns_id, int startup);
+extern int netlink_rule_change(struct nlmsghdr *h, ns_id_t ns_id, int startup);
/*
* Get to know existing PBR rules in the kernel - typically called at startup.