zebra: MAC and Neighbor (ARP/ND) handling

Implement handling of MACs and Neighbors (ARP/ND entries) in zebra:
- MAC and Neighbor database handlers
- Read MACs and Neighbors from the kernel, when needed and create
entries in zebra's MAC and Neighbor databases.
- Handle add/update/delete notifications from the kernel for MACs and
Neighbors and update zebra's database appropriately
- Inform locally learnt MACs and Neighbors to client
- Handle MACIP add/delete from client and install appriporiate entries
into the kernel
- Since Neighbor entries will be installed on an SVI, implement the
needed mappings

NOTE: kernel interface is only implemented for Linux/netlink

Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by:   Donald Sharp <sharpd@cumulusnetworks.com>
This commit is contained in:
vivek 2017-05-14 22:44:13 -07:00 committed by Donald Sharp
parent 4122e25286
commit 2232a77c2b
16 changed files with 2706 additions and 21 deletions

View File

@ -951,6 +951,10 @@ static const struct zebra_desc_table command_types[] = {
DESC_ENTRY (ZEBRA_VNI_DEL),
DESC_ENTRY (ZEBRA_REMOTE_VTEP_ADD),
DESC_ENTRY (ZEBRA_REMOTE_VTEP_DEL),
DESC_ENTRY (ZEBRA_MACIP_ADD),
DESC_ENTRY (ZEBRA_MACIP_DEL),
DESC_ENTRY (ZEBRA_REMOTE_MACIP_ADD),
DESC_ENTRY (ZEBRA_REMOTE_MACIP_DEL),
};
#undef DESC_ENTRY

View File

@ -101,6 +101,10 @@ typedef enum {
ZEBRA_VNI_DEL,
ZEBRA_REMOTE_VTEP_ADD,
ZEBRA_REMOTE_VTEP_DEL,
ZEBRA_MACIP_ADD,
ZEBRA_MACIP_DEL,
ZEBRA_REMOTE_MACIP_ADD,
ZEBRA_REMOTE_MACIP_DEL,
} zebra_message_types_t;
struct redist_proto

View File

@ -847,6 +847,7 @@ void
if_up (struct interface *ifp)
{
struct zebra_if *zif;
struct interface *link_if;
zif = ifp->info;
zif->up_count++;
@ -882,8 +883,23 @@ if_up (struct interface *ifp)
zebra_vrf_static_route_interface_fixup (ifp);
/* Handle interface up for specific types for EVPN. Non-VxLAN interfaces
* are checked to see if (remote) neighbor entries need to be installed
* on them for ARP suppression.
*/
if (IS_ZEBRA_IF_VXLAN (ifp))
zebra_vxlan_if_up (ifp);
else if (IS_ZEBRA_IF_BRIDGE (ifp))
{
link_if = ifp;
zebra_vxlan_svi_up (ifp, link_if);
}
else if (IS_ZEBRA_IF_VLAN (ifp))
{
link_if = zif->link;
if (link_if)
zebra_vxlan_svi_up (ifp, link_if);
}
}
/* Interface goes down. We have to manage different behavior of based
@ -892,13 +908,30 @@ void
if_down (struct interface *ifp)
{
struct zebra_if *zif;
struct interface *link_if;
zif = ifp->info;
zif->down_count++;
quagga_timestamp (2, zif->down_last, sizeof (zif->down_last));
/* Handle interface down for specific types for EVPN. Non-VxLAN interfaces
* are checked to see if (remote) neighbor entries need to be purged
* for ARP suppression.
*/
if (IS_ZEBRA_IF_VXLAN (ifp))
zebra_vxlan_if_down (ifp);
else if (IS_ZEBRA_IF_BRIDGE (ifp))
{
link_if = ifp;
zebra_vxlan_svi_down (ifp, link_if);
}
else if (IS_ZEBRA_IF_VLAN (ifp))
{
link_if = zif->link;
if (link_if)
zebra_vxlan_svi_down (ifp, link_if);
}
/* Notify to the protocol daemons. */
zebra_interface_down_update (ifp);

View File

@ -269,6 +269,12 @@ netlink_information_fetch (struct sockaddr_nl *snl, struct nlmsghdr *h,
case RTM_DELADDR:
return netlink_interface_addr (snl, h, ns_id, startup);
break;
case RTM_NEWNEIGH:
return netlink_neigh_change (snl, h, ns_id);
break;
case RTM_DELNEIGH:
return netlink_neigh_change (snl, h, ns_id);
break;
default:
zlog_warn ("Unknown netlink nlmsg_type %d vrf %u\n", h->nlmsg_type,
ns_id);
@ -297,17 +303,21 @@ static void netlink_install_filter (int sock, __u32 pid)
struct sock_filter filter[] = {
/* 0: ldh [4] */
BPF_STMT(BPF_LD|BPF_ABS|BPF_H, offsetof(struct nlmsghdr, nlmsg_type)),
/* 1: jeq 0x18 jt 3 jf 6 */
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_NEWROUTE), 1, 0),
/* 2: jeq 0x19 jt 3 jf 6 */
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_DELROUTE), 0, 3),
/* 3: ldw [12] */
/* 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] */
BPF_STMT(BPF_LD|BPF_ABS|BPF_W, offsetof(struct nlmsghdr, nlmsg_pid)),
/* 4: jeq XX jt 5 jf 6 */
/* 6: jeq XX jt 7 jf 8 */
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htonl(pid), 0, 1),
/* 5: ret 0 (skip) */
/* 7: ret 0 (skip) */
BPF_STMT(BPF_RET|BPF_K, 0),
/* 6: ret 0xffff (keep) */
/* 8: ret 0xffff (keep) */
BPF_STMT(BPF_RET|BPF_K, 0xffff),
};
@ -786,7 +796,7 @@ kernel_init (struct zebra_ns *zns)
/* Initialize netlink sockets */
groups = RTMGRP_LINK | RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_IFADDR |
RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFADDR |
RTMGRP_IPV4_MROUTE;
RTMGRP_IPV4_MROUTE | RTMGRP_NEIGH;
snprintf (zns->netlink.name, sizeof (zns->netlink.name),
"netlink-listen (NS %u)", zns->ns_id);

View File

@ -24,6 +24,7 @@
#include "prefix.h"
#include "if.h"
#include "vlan.h"
#include "vxlan.h"
#include "zebra/rib.h"
#include "zebra/zebra_ns.h"
@ -46,4 +47,13 @@ extern int kernel_add_vtep (vni_t vni, struct interface *ifp,
struct in_addr *vtep_ip);
extern int kernel_del_vtep (vni_t vni, struct interface *ifp,
struct in_addr *vtep_ip);
extern int kernel_add_mac (struct interface *ifp, vlanid_t vid,
struct ethaddr *mac, struct in_addr vtep_ip);
extern int kernel_del_mac (struct interface *ifp, vlanid_t vid,
struct ethaddr *mac, struct in_addr vtep_ip, int local);
extern int kernel_add_neigh (struct interface *ifp, struct ipaddr *ip,
struct ethaddr *mac);
extern int kernel_del_neigh (struct interface *ifp, struct ipaddr *ip);
#endif /* _ZEBRA_RT_H */

View File

@ -56,6 +56,7 @@
#include "zebra/kernel_netlink.h"
#include "zebra/rt_netlink.h"
#include "zebra/zebra_mroute.h"
#include "zebra/zebra_vxlan.h"
/* TODO - Temporary definitions, need to refine. */
@ -94,8 +95,22 @@
#ifndef NDA_MASTER
#define NDA_MASTER 9
#endif
#ifndef NTF_SELF
#define NTF_SELF 0x02
#endif
#ifndef NTF_EXT_LEARNED
#define NTF_EXT_LEARNED 0x10
#endif
#ifndef NDA_VLAN
#define NDA_VLAN 5
#endif
/* End of temporary definitions */
static vlanid_t filter_vlan = 0;
struct gw_family_t
{
u_int16_t filler;
@ -1622,6 +1637,636 @@ kernel_del_vtep (vni_t vni, struct interface *ifp, struct in_addr *vtep_ip)
return netlink_vxlan_flood_list_update (ifp, vtep_ip, RTM_DELNEIGH);
}
#ifndef NDA_RTA
#define NDA_RTA(r) \
((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg))))
#endif
static int
netlink_macfdb_change (struct sockaddr_nl *snl, struct nlmsghdr *h, int len)
{
struct ndmsg *ndm;
struct interface *ifp;
struct zebra_if *zif;
struct zebra_vrf *zvrf;
struct rtattr *tb[NDA_MAX + 1];
struct interface *br_if;
struct ethaddr mac;
vlanid_t vid = 0;
struct prefix vtep_ip;
int vid_present = 0, dst_present = 0;
char buf[ETHER_ADDR_STRLEN];
char vid_buf[20];
char dst_buf[30];
ndm = NLMSG_DATA (h);
/* The interface should exist. */
ifp = if_lookup_by_index_per_ns (zebra_ns_lookup (NS_DEFAULT), ndm->ndm_ifindex);
if (!ifp)
return 0;
/* Locate VRF corresponding to interface. We only process MAC notifications
* if EVPN is enabled on this VRF.
*/
zvrf = vrf_info_lookup(ifp->vrf_id);
if (!zvrf || !EVPN_ENABLED(zvrf))
return 0;
if (!ifp->info)
return 0;
/* The interface should be something we're interested in. */
if (!IS_ZEBRA_IF_BRIDGE_SLAVE(ifp))
return 0;
/* Drop "permanent" entries. */
if (ndm->ndm_state & NUD_PERMANENT)
return 0;
zif = (struct zebra_if *)ifp->info;
if ((br_if = zif->brslave_info.br_if) == NULL)
{
zlog_warn ("%s family %s IF %s(%u) brIF %u - no bridge master",
nl_msg_type_to_str (h->nlmsg_type),
nl_family_to_str (ndm->ndm_family),
ifp->name, ndm->ndm_ifindex,
zif->brslave_info.bridge_ifindex);
return 0;
}
/* Parse attributes and extract fields of interest. */
memset (tb, 0, sizeof tb);
netlink_parse_rtattr (tb, NDA_MAX, NDA_RTA (ndm), len);
if (!tb[NDA_LLADDR])
{
zlog_warn ("%s family %s IF %s(%u) brIF %u - no LLADDR",
nl_msg_type_to_str (h->nlmsg_type),
nl_family_to_str (ndm->ndm_family),
ifp->name, ndm->ndm_ifindex,
zif->brslave_info.bridge_ifindex);
return 0;
}
if (RTA_PAYLOAD (tb[NDA_LLADDR]) != ETHER_ADDR_LEN)
{
zlog_warn ("%s family %s IF %s(%u) brIF %u - LLADDR is not MAC, len %ld",
nl_msg_type_to_str (h->nlmsg_type),
nl_family_to_str (ndm->ndm_family),
ifp->name, ndm->ndm_ifindex,
zif->brslave_info.bridge_ifindex,
RTA_PAYLOAD (tb[NDA_LLADDR]));
return 0;
}
memcpy (&mac, RTA_DATA (tb[NDA_LLADDR]), ETHER_ADDR_LEN);
if ((NDA_VLAN <= NDA_MAX) && tb[NDA_VLAN])
{
vid_present = 1;
vid = *(u_int16_t *) RTA_DATA(tb[NDA_VLAN]);
sprintf (vid_buf, " VLAN %u", vid);
}
if (tb[NDA_DST])
{
/* TODO: Only IPv4 supported now. */
dst_present = 1;
vtep_ip.family = AF_INET;
vtep_ip.prefixlen = IPV4_MAX_BITLEN;
memcpy (&(vtep_ip.u.prefix4.s_addr), RTA_DATA (tb[NDA_DST]), IPV4_MAX_BYTELEN);
sprintf (dst_buf, " dst %s", inet_ntoa (vtep_ip.u.prefix4));
}
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug ("Rx %s family %s IF %s(%u)%s MAC %s%s",
nl_msg_type_to_str (h->nlmsg_type),
nl_family_to_str (ndm->ndm_family),
ifp->name, ndm->ndm_ifindex,
vid_present ? vid_buf : "",
prefix_mac2str (&mac, buf, sizeof (buf)),
dst_present ? dst_buf: "");
if (filter_vlan && vid != filter_vlan)
return 0;
/* If add or update, do accordingly if learnt on a "local" interface; if
* the notification is over VxLAN, this has to be related to multi-homing,
* so perform an implicit delete of any local entry (if it exists).
*/
if (h->nlmsg_type == RTM_NEWNEIGH)
{
/* Drop "permanent" entries. */
if (ndm->ndm_state & NUD_PERMANENT)
return 0;
if (IS_ZEBRA_IF_VXLAN(ifp))
return zebra_vxlan_check_del_local_mac (ifp, br_if, &mac, vid);
return zebra_vxlan_local_mac_add_update (ifp, br_if, &mac, vid);
}
/* This is a delete notification.
* 1. For a MAC over VxLan, check if it needs to be refreshed(readded)
* 2. For a MAC over "local" interface, delete the mac
* Note: We will get notifications from both bridge driver and VxLAN driver.
* Ignore the notification from VxLan driver as it is also generated
* when mac moves from remote to local.
*/
if (dst_present)
return 0;
if (IS_ZEBRA_IF_VXLAN(ifp))
return zebra_vxlan_check_readd_remote_mac (ifp, br_if, &mac, vid);
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)
{
int len;
struct ndmsg *ndm;
if (h->nlmsg_type != RTM_NEWNEIGH)
return 0;
/* Length validity. */
len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ndmsg));
if (len < 0)
return -1;
/* We are interested only in AF_BRIDGE notifications. */
ndm = NLMSG_DATA (h);
if (ndm->ndm_family != AF_BRIDGE)
return 0;
return netlink_macfdb_change (snl, h, len);
}
/* Request for MAC FDB information from the kernel */
static int
netlink_request_macs (struct zebra_ns *zns, int family, int type,
ifindex_t master_ifindex)
{
struct
{
struct nlmsghdr n;
struct ifinfomsg ifm;
char buf[256];
} req;
/* Form the request, specifying filter (rtattr) if needed. */
memset (&req, 0, sizeof (req));
req.n.nlmsg_type = type;
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
req.ifm.ifi_family = family;
if (master_ifindex)
addattr32 (&req.n, sizeof(req), IFLA_MASTER, master_ifindex);
return netlink_request (&zns->netlink_cmd, &req.n);
}
/*
* MAC forwarding database read using netlink interface. This is invoked
* at startup.
*/
int
netlink_macfdb_read (struct zebra_ns *zns)
{
int ret;
/* Get bridge FDB table. */
ret = netlink_request_macs (zns, AF_BRIDGE, RTM_GETNEIGH, 0);
if (ret < 0)
return ret;
/* We are reading entire table. */
filter_vlan = 0;
ret = netlink_parse_info (netlink_macfdb_table, &zns->netlink_cmd, zns, 0, 1);
return ret;
}
/*
* MAC forwarding database read using netlink interface. This is for a
* specific bridge and matching specific access VLAN (if VLAN-aware bridge).
*/
int
netlink_macfdb_read_for_bridge (struct zebra_ns *zns, struct interface *ifp,
struct interface *br_if)
{
struct zebra_if *br_zif;
struct zebra_if *zif;
struct zebra_l2info_vxlan *vxl;
int ret = 0;
/* Save VLAN we're filtering on, if needed. */
br_zif = (struct zebra_if *) br_if->info;
zif = (struct zebra_if *) ifp->info;
vxl = &zif->l2info.vxl;
if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif))
filter_vlan = vxl->access_vlan;
/* Get bridge FDB table for specific bridge - we do the VLAN filtering. */
ret = netlink_request_macs (zns, AF_BRIDGE, RTM_GETNEIGH, br_if->ifindex);
if (ret < 0)
return ret;
ret = netlink_parse_info (netlink_macfdb_table, &zns->netlink_cmd, zns, 0, 0);
/* Reset VLAN filter. */
filter_vlan = 0;
return ret;
}
static int
netlink_macfdb_update (struct interface *ifp, vlanid_t vid,
struct ethaddr *mac,
struct in_addr vtep_ip,
int local, int cmd)
{
struct zebra_ns *zns = zebra_ns_lookup (NS_DEFAULT);
struct
{
struct nlmsghdr n;
struct ndmsg ndm;
char buf[256];
} req;
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, dst_present = 0;
char vid_buf[20];
char dst_buf[30];
zif = ifp->info;
if ((br_if = zif->brslave_info.br_if) == NULL)
{
zlog_warn ("MAC %s on IF %s(%u) - no mapping to bridge",
(cmd == RTM_NEWNEIGH) ? "add" : "del",
ifp->name, ifp->ifindex);
return -1;
}
memset(&req.n, 0, sizeof(req.n));
memset(&req.ndm, 0, sizeof(req.ndm));
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg));
req.n.nlmsg_flags = NLM_F_REQUEST;
if (cmd == RTM_NEWNEIGH)
req.n.nlmsg_flags |= (NLM_F_CREATE | NLM_F_REPLACE);
req.n.nlmsg_type = cmd;
req.ndm.ndm_family = AF_BRIDGE;
req.ndm.ndm_flags |= NTF_SELF | NTF_MASTER;
req.ndm.ndm_state = NUD_REACHABLE;
req.ndm.ndm_flags |= NTF_EXT_LEARNED;
addattr_l (&req.n, sizeof (req), NDA_LLADDR, mac, 6);
req.ndm.ndm_ifindex = ifp->ifindex;
if (!local)
{
dst_alen = 4; // TODO: hardcoded
addattr_l (&req.n, sizeof (req), NDA_DST, &vtep_ip, dst_alen);
dst_present = 1;
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)
{
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);
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug ("Tx %s family %s IF %s(%u)%s MAC %s%s",
nl_msg_type_to_str (cmd),
nl_family_to_str (req.ndm.ndm_family),
ifp->name, ifp->ifindex,
vid_present ? vid_buf : "",
prefix_mac2str (mac, buf, sizeof (buf)),
dst_present ? dst_buf : "");
return netlink_talk (netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, 0);
}
#define NUD_VALID (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)
{
struct ndmsg *ndm;
struct interface *ifp;
struct zebra_if *zif;
struct zebra_vrf *zvrf;
struct rtattr *tb[NDA_MAX + 1];
struct interface *link_if;
struct ethaddr mac;
struct ipaddr ip;
char buf[ETHER_ADDR_STRLEN];
char buf2[INET6_ADDRSTRLEN];
int mac_present = 0;
u_char ext_learned;
ndm = NLMSG_DATA (h);
/* The interface should exist. */
ifp = if_lookup_by_index_per_ns (zebra_ns_lookup (NS_DEFAULT), ndm->ndm_ifindex);
if (!ifp)
return 0;
/* Locate VRF corresponding to interface. We only process neigh notifications
* if EVPN is enabled on this VRF.
*/
zvrf = vrf_info_lookup(ifp->vrf_id);
if (!zvrf || !EVPN_ENABLED(zvrf))
return 0;
if (!ifp->info)
return 0;
/* Drop "permanent" entries. */
if (ndm->ndm_state & NUD_PERMANENT)
return 0;
zif = (struct zebra_if *)ifp->info;
/* The neighbor is present on an SVI. From this, we locate the underlying
* bridge because we're only interested in neighbors on a VxLAN bridge.
* The bridge is located based on the nature of the SVI:
* (a) In the case of a VLAN-aware bridge, the SVI is a L3 VLAN interface
* and is linked to the bridge
* (b) In the case of a VLAN-unaware bridge, the SVI is the bridge inteface
* itself
*/
if (IS_ZEBRA_IF_VLAN(ifp))
{
link_if = zif->link;
if (!link_if)
return 0;
}
else if (IS_ZEBRA_IF_BRIDGE(ifp))
link_if = ifp;
else
return 0;
/* Parse attributes and extract fields of interest. */
memset (tb, 0, sizeof tb);
netlink_parse_rtattr (tb, NDA_MAX, NDA_RTA (ndm), len);
if (!tb[NDA_DST])
{
zlog_warn ("%s family %s IF %s(%u) - no DST",
nl_msg_type_to_str (h->nlmsg_type),
nl_family_to_str (ndm->ndm_family),
ifp->name, ndm->ndm_ifindex);
return 0;
}
memset (&mac, 0, sizeof (struct ethaddr));
memset (&ip, 0, sizeof (struct ipaddr));
ip.ipa_type = (ndm->ndm_family == AF_INET) ? IPADDR_V4 : IPADDR_V6;
memcpy (&ip.ip.addr, RTA_DATA(tb[NDA_DST]), RTA_PAYLOAD(tb[NDA_DST]));
if (h->nlmsg_type == RTM_NEWNEIGH)
{
if (tb[NDA_LLADDR])
{
if (RTA_PAYLOAD (tb[NDA_LLADDR]) != ETHER_ADDR_LEN)
{
zlog_warn ("%s family %s IF %s(%u) - LLADDR is not MAC, len %ld",
nl_msg_type_to_str (h->nlmsg_type),
nl_family_to_str (ndm->ndm_family),
ifp->name, ndm->ndm_ifindex,
RTA_PAYLOAD (tb[NDA_LLADDR]));
return 0;
}
mac_present = 1;
memcpy (&mac, RTA_DATA (tb[NDA_LLADDR]), ETHER_ADDR_LEN);
}
ext_learned = (ndm->ndm_flags & NTF_EXT_LEARNED) ? 1 : 0;
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug ("Rx %s family %s IF %s(%u) IP %s MAC %s state 0x%x flags 0x%x",
nl_msg_type_to_str (h->nlmsg_type),
nl_family_to_str (ndm->ndm_family),
ifp->name, ndm->ndm_ifindex,
ipaddr2str (&ip, buf2, sizeof(buf2)),
mac_present ? prefix_mac2str (&mac, buf, sizeof (buf)) : "",
ndm->ndm_state, ndm->ndm_flags);
/* If the neighbor state is valid for use, process as an add or update
* else process as a delete. Note that the delete handling may result
* in re-adding the neighbor if it is a valid "remote" neighbor.
*/
if (ndm->ndm_state & NUD_VALID)
return zebra_vxlan_local_neigh_add_update (ifp, link_if,
&ip, &mac,
ndm->ndm_state, ext_learned);
return zebra_vxlan_local_neigh_del (ifp, link_if, &ip);
}
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug ("Rx %s family %s IF %s(%u) IP %s",
nl_msg_type_to_str (h->nlmsg_type),
nl_family_to_str (ndm->ndm_family),
ifp->name, ndm->ndm_ifindex,
ipaddr2str (&ip, buf2, sizeof(buf2)));
/* Process the delete - it may result in re-adding the neighbor if it is
* a valid "remote" neighbor.
*/
return zebra_vxlan_local_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)
{
int len;
struct ndmsg *ndm;
if (h->nlmsg_type != RTM_NEWNEIGH)
return 0;
/* Length validity. */
len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ndmsg));
if (len < 0)
return -1;
/* We are interested only in AF_INET or AF_INET6 notifications. */
ndm = NLMSG_DATA (h);
if (ndm->ndm_family != AF_INET && ndm->ndm_family != AF_INET6)
return 0;
return netlink_neigh_change (snl, h, len);
}
/* Request for IP neighbor information from the kernel */
static int
netlink_request_neigh (struct zebra_ns *zns, int family, int type,
ifindex_t ifindex)
{
struct
{
struct nlmsghdr n;
struct ndmsg ndm;
char buf[256];
} req;
/* Form the request, specifying filter (rtattr) if needed. */
memset (&req, 0, sizeof (req));
req.n.nlmsg_type = type;
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg));
req.ndm.ndm_family = family;
if (ifindex)
addattr32 (&req.n, sizeof(req), NDA_IFINDEX, ifindex);
return netlink_request (&zns->netlink_cmd, &req.n);
}
/*
* IP Neighbor table read using netlink interface. This is invoked
* at startup.
*/
int
netlink_neigh_read (struct zebra_ns *zns)
{
int ret;
/* Get IP neighbor table. */
ret = netlink_request_neigh (zns, AF_UNSPEC, RTM_GETNEIGH, 0);
if (ret < 0)
return ret;
ret = netlink_parse_info (netlink_neigh_table, &zns->netlink_cmd, zns, 0, 1);
return ret;
}
/*
* IP Neighbor table read using netlink interface. This is for a specific
* VLAN device.
*/
int
netlink_neigh_read_for_vlan (struct zebra_ns *zns, struct interface *vlan_if)
{
int ret = 0;
ret = netlink_request_neigh (zns, AF_UNSPEC, RTM_GETNEIGH, vlan_if->ifindex);
if (ret < 0)
return ret;
ret = netlink_parse_info (netlink_neigh_table, &zns->netlink_cmd, zns, 0, 0);
return ret;
}
int
netlink_neigh_change (struct sockaddr_nl *snl, struct nlmsghdr *h,
ns_id_t ns_id)
{
int len;
struct ndmsg *ndm;
if (!(h->nlmsg_type == RTM_NEWNEIGH || h->nlmsg_type == RTM_DELNEIGH))
return 0;
/* Length validity. */
len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ndmsg));
if (len < 0)
return -1;
/* 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);
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);
return 0;
}
static int
netlink_neigh_update2 (struct interface *ifp, struct ipaddr *ip,
struct ethaddr *mac, u_int32_t flags, int cmd)
{
struct {
struct nlmsghdr n;
struct ndmsg ndm;
char buf[256];
} req;
int ipa_len;
struct zebra_ns *zns = zebra_ns_lookup (NS_DEFAULT);
char buf[INET6_ADDRSTRLEN];
char buf2[ETHER_ADDR_STRLEN];
memset(&req.n, 0, sizeof(req.n));
memset(&req.ndm, 0, sizeof(req.ndm));
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg));
req.n.nlmsg_flags = NLM_F_REQUEST;
if (cmd == RTM_NEWNEIGH)
req.n.nlmsg_flags |= (NLM_F_CREATE | NLM_F_REPLACE);
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 = flags;
req.ndm.ndm_ifindex = ifp->ifindex;
req.ndm.ndm_type = RTN_UNICAST;
req.ndm.ndm_flags = NTF_EXT_LEARNED;
ipa_len = IS_IPADDR_V4(ip) ? IPV4_MAX_BYTELEN : IPV6_MAX_BYTELEN;
addattr_l(&req.n, sizeof(req), NDA_DST, &ip->ip.addr, ipa_len);
if (mac)
addattr_l (&req.n, sizeof (req), NDA_LLADDR, mac, 6);
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug ("Tx %s family %s IF %s(%u) Neigh %s MAC %s",
nl_msg_type_to_str (cmd),
nl_family_to_str (req.ndm.ndm_family),
ifp->name, ifp->ifindex,
ipaddr2str (ip, buf, sizeof(buf)),
mac ? prefix_mac2str (mac, buf2, sizeof (buf2)) : "null");
return netlink_talk (netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, 0);
}
int
kernel_add_mac (struct interface *ifp, vlanid_t vid,
struct ethaddr *mac, struct in_addr vtep_ip)
{
return netlink_macfdb_update (ifp, vid, mac, vtep_ip, 0, RTM_NEWNEIGH);
}
int
kernel_del_mac (struct interface *ifp, vlanid_t vid,
struct ethaddr *mac, struct in_addr vtep_ip, int local)
{
return netlink_macfdb_update (ifp, vid, mac, vtep_ip, local, RTM_DELNEIGH);
}
int kernel_add_neigh (struct interface *ifp, struct ipaddr *ip,
struct ethaddr *mac)
{
return netlink_neigh_update2 (ifp, ip, mac, NUD_REACHABLE,
RTM_NEWNEIGH);
}
int kernel_del_neigh (struct interface *ifp, struct ipaddr *ip)
{
return netlink_neigh_update2 (ifp, ip, NULL, 0, RTM_DELNEIGH);
}
/*
* MPLS label forwarding table change via netlink interface.
*/

View File

@ -51,6 +51,15 @@ extern int netlink_route_change (struct sockaddr_nl *snl, 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_macfdb_read (struct zebra_ns *zns);
extern int netlink_macfdb_read_for_bridge (struct zebra_ns *zns,
struct interface *ifp, struct interface *br_if);
extern int netlink_neigh_read (struct zebra_ns *zns);
extern int netlink_neigh_read_for_vlan (struct zebra_ns *zns,
struct interface *vlan_if);
#endif /* HAVE_NETLINK */
#endif /* _ZEBRA_RT_NETLINK_H */

View File

@ -441,3 +441,28 @@ kernel_del_vtep (vni_t vni, struct interface *ifp, struct in_addr *vtep_ip)
{
return 0;
}
int
kernel_add_mac (struct interface *ifp, vlanid_t vid,
struct ethaddr *mac, struct in_addr vtep_ip)
{
return 0;
}
int
kernel_del_mac (struct interface *ifp, vlanid_t vid,
struct ethaddr *mac, struct in_addr vtep_ip, int local)
{
return 0;
}
int kernel_add_neigh (struct interface *ifp, struct ipaddr *ip,
struct ethaddr *mac)
{
return 0;
}
int kernel_del_neigh (struct interface *ifp, struct ipaddr *ip)
{
return 0;
}

View File

@ -237,3 +237,23 @@ route_read (struct zebra_ns *zns)
exit:
close (dev);
}
/* Only implemented for netlink method */
void
macfdb_read (struct zebra_ns *zns)
{
}
void macfdb_read_for_bridge (struct zebra_ns *zns, struct interface *ifp,
struct interface *br_if)
{
}
void
neigh_read (struct zebra_ns *zns)
{
}
void neigh_read_for_vlan (struct zebra_ns *zns, struct interface *vlan_if)
{
}

View File

@ -29,3 +29,24 @@ void route_read (struct zebra_ns *zns)
{
netlink_route_read (zns);
}
void macfdb_read (struct zebra_ns *zns)
{
netlink_macfdb_read (zns);
}
void macfdb_read_for_bridge (struct zebra_ns *zns, struct interface *ifp,
struct interface *br_if)
{
netlink_macfdb_read_for_bridge (zns, ifp, br_if);
}
void neigh_read (struct zebra_ns *zns)
{
netlink_neigh_read (zns);
}
void neigh_read_for_vlan (struct zebra_ns *zns, struct interface *vlan_if)
{
netlink_neigh_read_for_vlan (zns, vlan_if);
}

View File

@ -83,3 +83,23 @@ route_read (struct zebra_ns *zns)
return;
}
/* Only implemented for the netlink method. */
void
macfdb_read (struct zebra_ns *zns)
{
}
void macfdb_read_for_bridge (struct zebra_ns *zns, struct interface *ifp,
struct interface *br_if)
{
}
void
neigh_read (struct zebra_ns *zns)
{
}
void neigh_read_for_vlan (struct zebra_ns *zns, struct interface *vlan_if)
{
}

File diff suppressed because it is too large Load Diff

View File

@ -42,6 +42,33 @@
#define ZEBRA_VXLIF_MASTER_CHANGE 0x2
#define ZEBRA_VXLIF_VLAN_CHANGE 0x4
extern int zebra_vxlan_svi_up (struct interface *ifp, struct interface *link_if);
extern int zebra_vxlan_svi_down (struct interface *ifp, struct interface *link_if);
extern int zebra_vxlan_local_neigh_add_update (struct interface *ifp,
struct interface *link_if,
struct ipaddr *ip,
struct ethaddr *macaddr,
u_int16_t state,
u_char ext_learned);
extern int zebra_vxlan_local_neigh_del (struct interface *ifp,
struct interface *link_if,
struct ipaddr *ip);
extern int zebra_vxlan_remote_macip_add (struct zserv *client, int sock,
u_short length, struct zebra_vrf *zvrf);
extern int zebra_vxlan_remote_macip_del (struct zserv *client, int sock,
u_short length, struct zebra_vrf *zvrf);
extern int zebra_vxlan_local_mac_add_update (struct interface *ifp,
struct interface *br_if,
struct ethaddr *mac, vlanid_t vid);
extern int zebra_vxlan_local_mac_del (struct interface *ifp,
struct interface *br_if,
struct ethaddr *mac, vlanid_t vid);
extern int zebra_vxlan_check_readd_remote_mac (struct interface *ifp,
struct interface *br_if,
struct ethaddr *mac, vlanid_t vid);
extern int zebra_vxlan_check_del_local_mac (struct interface *ifp,
struct interface *br_if,
struct ethaddr *mac, vlanid_t vid);
extern int zebra_vxlan_if_up (struct interface *ifp);
extern int zebra_vxlan_if_down (struct interface *ifp);
extern int zebra_vxlan_if_add (struct interface *ifp);

View File

@ -30,6 +30,56 @@
#include "zebra/zebra_l2.h"
#include "zebra/zebra_vxlan.h"
int zebra_vxlan_svi_up (struct interface *ifp, struct interface *link_if)
{
return 0;
}
int zebra_vxlan_svi_down (struct interface *ifp, struct interface *link_if)
{
return 0;
}
int zebra_vxlan_remote_macip_add (struct zserv *client, int sock,
u_short length, struct zebra_vrf *zvrf)
{
return 0;
}
int zebra_vxlan_remote_macip_del (struct zserv *client, int sock,
u_short length, struct zebra_vrf *zvrf)
{
return 0;
}
int zebra_vxlan_local_mac_add_update (struct interface *ifp,
struct interface *br_if,
struct ethaddr *mac, vlanid_t vid)
{
return 0;
}
int zebra_vxlan_local_mac_del (struct interface *ifp,
struct interface *br_if,
struct ethaddr *mac, vlanid_t vid)
{
return 0;
}
int zebra_vxlan_check_readd_remote_mac (struct interface *ifp,
struct interface *br_if,
struct ethaddr *mac, vlanid_t vid)
{
return 0;
}
int zebra_vxlan_check_del_local_mac (struct interface *ifp,
struct interface *br_if,
struct ethaddr *mac, vlanid_t vid)
{
return 0;
}
int
zebra_vxlan_if_up (struct interface *ifp)
{

View File

@ -2444,6 +2444,12 @@ zebra_client_read (struct thread *thread)
case ZEBRA_REMOTE_VTEP_DEL:
zebra_vxlan_remote_vtep_del (client, sock, length, zvrf);
break;
case ZEBRA_REMOTE_MACIP_ADD:
zebra_vxlan_remote_macip_add (client, sock, length, zvrf);
break;
case ZEBRA_REMOTE_MACIP_DEL:
zebra_vxlan_remote_macip_del (client, sock, length, zvrf);
break;
default:
zlog_info ("Zebra received unknown command %d", command);
break;
@ -2737,6 +2743,9 @@ zebra_show_client_detail (struct vty *vty, struct zserv *client)
vty_outln (vty, "Interface Down Notifications: %d",client->ifdown_cnt);
vty_outln (vty, "VNI add notifications: %d", client->vniadd_cnt);
vty_outln (vty, "VNI delete notifications: %d", client->vnidel_cnt);
vty_outln (vty, "MAC-IP add notifications: %d", client->macipadd_cnt);
vty_outln (vty, "MAC-IP delete notifications: %d", client->macipdel_cnt);
vty_out (vty, VTYNL);
return;
}

View File

@ -107,6 +107,8 @@ struct zserv
u_int32_t bfd_client_reg_cnt;
u_int32_t vniadd_cnt;
u_int32_t vnidel_cnt;
u_int32_t macipadd_cnt;
u_int32_t macipdel_cnt;
time_t connect_time;
time_t last_read_time;
@ -147,6 +149,11 @@ extern void hostinfo_get (void);
extern void rib_init (void);
extern void interface_list (struct zebra_ns *);
extern void route_read (struct zebra_ns *);
extern void macfdb_read (struct zebra_ns *);
extern void macfdb_read_for_bridge (struct zebra_ns *, struct interface *,
struct interface *);
extern void neigh_read (struct zebra_ns *);
extern void neigh_read_for_vlan (struct zebra_ns *, struct interface *);
extern void kernel_init (struct zebra_ns *);
extern void kernel_terminate (struct zebra_ns *);
extern void zebra_route_map_init (void);