diff options
-rw-r--r-- | zebra/if_netlink.c | 1 | ||||
-rw-r--r-- | zebra/kernel_netlink.c | 1 | ||||
-rw-r--r-- | zebra/rt.h | 5 | ||||
-rw-r--r-- | zebra/rt_netlink.c | 134 | ||||
-rw-r--r-- | zebra/rt_netlink.h | 5 | ||||
-rw-r--r-- | zebra/rtread_getmsg.c | 9 | ||||
-rw-r--r-- | zebra/rtread_netlink.c | 11 | ||||
-rw-r--r-- | zebra/rtread_sysctl.c | 9 | ||||
-rw-r--r-- | zebra/zebra_vxlan.c | 46 |
9 files changed, 218 insertions, 3 deletions
diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index 4e49c1fc5..0cecce5e7 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -731,6 +731,7 @@ static int netlink_request_intf_addr(struct nlsock *netlink_cmd, int family, /* Form the request, specifying filter (rtattr) if needed. */ memset(&req, 0, sizeof(req)); req.n.nlmsg_type = type; + req.n.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST; req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); req.ifm.ifi_family = family; diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index 360f596b8..c88bfbb10 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -1032,7 +1032,6 @@ int netlink_request(struct nlsock *nl, struct nlmsghdr *n) } /* Fill common fields for all requests. */ - n->nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST; n->nlmsg_pid = nl->snl.nl_pid; n->nlmsg_seq = ++nl->seq; diff --git a/zebra/rt.h b/zebra/rt.h index f2b531400..0b14a3ef3 100644 --- a/zebra/rt.h +++ b/zebra/rt.h @@ -78,8 +78,13 @@ extern void kernel_terminate(struct zebra_ns *zns, bool complete); extern void macfdb_read(struct zebra_ns *zns); extern void macfdb_read_for_bridge(struct zebra_ns *zns, struct interface *ifp, struct interface *br_if); +extern void macfdb_read_specific_mac(struct zebra_ns *zns, + struct interface *br_if, + struct ethaddr *mac, vlanid_t vid); extern void neigh_read(struct zebra_ns *zns); extern void neigh_read_for_vlan(struct zebra_ns *zns, struct interface *ifp); +extern void neigh_read_specific_ip(struct ipaddr *ip, + struct interface *vlan_if); extern void route_read(struct zebra_ns *zns); #endif /* _ZEBRA_RT_H */ diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 45bc3b3ba..ce2d25862 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -879,6 +879,7 @@ static int netlink_request_route(struct zebra_ns *zns, int family, int type) /* Form the request, specifying filter (rtattr) if needed. */ memset(&req, 0, sizeof(req)); req.n.nlmsg_type = type; + req.n.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST; req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); req.rtm.rtm_family = family; @@ -2127,6 +2128,7 @@ static int netlink_request_macs(struct nlsock *netlink_cmd, int family, /* Form the request, specifying filter (rtattr) if needed. */ memset(&req, 0, sizeof(req)); req.n.nlmsg_type = type; + req.n.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST; req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); req.ifm.ifi_family = family; if (master_ifindex) @@ -2195,6 +2197,70 @@ int netlink_macfdb_read_for_bridge(struct zebra_ns *zns, struct interface *ifp, return ret; } + +/* Request for MAC FDB for a specific MAC address in VLAN from the kernel */ +static int netlink_request_specific_mac_in_bridge(struct zebra_ns *zns, + int family, + int type, + struct interface *br_if, + struct ethaddr *mac, + vlanid_t vid) +{ + struct { + struct nlmsghdr n; + struct ndmsg ndm; + char buf[256]; + } req; + struct zebra_if *br_zif; + char buf[ETHER_ADDR_STRLEN]; + + memset(&req, 0, sizeof(req)); + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)); + req.n.nlmsg_type = type; /* RTM_GETNEIGH */ + req.n.nlmsg_flags = NLM_F_REQUEST; + req.ndm.ndm_family = family; /* AF_BRIDGE */ + /* req.ndm.ndm_state = NUD_REACHABLE; */ + + addattr_l(&req.n, sizeof(req), NDA_LLADDR, mac, 6); + + 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); + + addattr32(&req.n, sizeof(req), NDA_MASTER, br_if->ifindex); + + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("%s: Tx family %s IF %s(%u) MAC %s vid %u", + __PRETTY_FUNCTION__, + nl_family_to_str(req.ndm.ndm_family), br_if->name, + br_if->ifindex, + prefix_mac2str(mac, buf, sizeof(buf)), vid); + + return netlink_request(&zns->netlink_cmd, &req.n); +} + +int netlink_macfdb_read_specific_mac(struct zebra_ns *zns, + struct interface *br_if, + struct ethaddr *mac, vlanid_t vid) +{ + int ret = 0; + struct zebra_dplane_info dp_info; + + zebra_dplane_info_from_zns(&dp_info, zns, true /*is_cmd*/); + + /* Get bridge FDB table for specific bridge - we do the VLAN filtering. + */ + ret = netlink_request_specific_mac_in_bridge(zns, AF_BRIDGE, + RTM_GETNEIGH, + br_if, mac, vid); + if (ret < 0) + return ret; + + ret = netlink_parse_info(netlink_macfdb_table, &zns->netlink_cmd, + &dp_info, 1, 0); + + 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) @@ -2454,6 +2520,7 @@ static int netlink_request_neigh(struct nlsock *netlink_cmd, int family, /* Form the request, specifying filter (rtattr) if needed. */ memset(&req, 0, sizeof(req)); req.n.nlmsg_type = type; + req.n.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST; req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)); req.ndm.ndm_family = family; if (ifindex) @@ -2505,6 +2572,73 @@ int netlink_neigh_read_for_vlan(struct zebra_ns *zns, struct interface *vlan_if) return ret; } +/* + * Request for a specific IP in VLAN (SVI) device from IP Neighbor table, + * read using netlink interface. + */ +static int netlink_request_specific_neigh_in_vlan(struct zebra_ns *zns, + int type, struct ipaddr *ip, + ifindex_t ifindex) +{ + struct { + struct nlmsghdr n; + struct ndmsg ndm; + char buf[256]; + } req; + int ipa_len; + + /* Form the request, specifying filter (rtattr) if needed. */ + memset(&req, 0, sizeof(req)); + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)); + req.n.nlmsg_flags = NLM_F_REQUEST; + req.n.nlmsg_type = type; /* RTM_GETNEIGH */ + req.ndm.ndm_ifindex = ifindex; + + if (IS_IPADDR_V4(ip)) { + ipa_len = IPV4_MAX_BYTELEN; + req.ndm.ndm_family = AF_INET; + + } else { + ipa_len = IPV6_MAX_BYTELEN; + req.ndm.ndm_family = AF_INET6; + } + + addattr_l(&req.n, sizeof(req), NDA_DST, &ip->ip.addr, ipa_len); + + return netlink_request(&zns->netlink_cmd, &req.n); +} + +int netlink_neigh_read_specific_ip(struct ipaddr *ip, + struct interface *vlan_if) +{ + int ret = 0; + struct zebra_ns *zns; + struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(vlan_if->vrf_id); + char buf[INET6_ADDRSTRLEN]; + struct zebra_dplane_info dp_info; + + zns = zvrf->zns; + + zebra_dplane_info_from_zns(&dp_info, zns, true /*is_cmd*/); + + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("%s: neigh request IF %s(%u) IP %s vrf_id %u", + __PRETTY_FUNCTION__, vlan_if->name, + vlan_if->ifindex, + ipaddr2str(ip, buf, sizeof(buf)), + vlan_if->vrf_id); + + ret = netlink_request_specific_neigh_in_vlan(zns, RTM_GETNEIGH, ip, + vlan_if->ifindex); + if (ret < 0) + return ret; + + ret = netlink_parse_info(netlink_neigh_table, &zns->netlink_cmd, + &dp_info, 1, 0); + + return ret; +} + int netlink_neigh_change(struct nlmsghdr *h, ns_id_t ns_id) { int len; diff --git a/zebra/rt_netlink.h b/zebra/rt_netlink.h index 914a0b5d7..473ad98a3 100644 --- a/zebra/rt_netlink.h +++ b/zebra/rt_netlink.h @@ -73,6 +73,11 @@ extern int netlink_macfdb_read_for_bridge(struct zebra_ns *zns, extern int netlink_neigh_read(struct zebra_ns *zns); extern int netlink_neigh_read_for_vlan(struct zebra_ns *zns, struct interface *vlan_if); +extern int netlink_macfdb_read_specific_mac(struct zebra_ns *zns, + struct interface *br_if, + struct ethaddr *mac, uint16_t vid); +extern int netlink_neigh_read_specific_ip(struct ipaddr *ip, + struct interface *vlan_if); #endif /* HAVE_NETLINK */ diff --git a/zebra/rtread_getmsg.c b/zebra/rtread_getmsg.c index c1bd68f9d..725bb63a0 100644 --- a/zebra/rtread_getmsg.c +++ b/zebra/rtread_getmsg.c @@ -261,6 +261,11 @@ void macfdb_read_for_bridge(struct zebra_ns *zns, struct interface *ifp, { } +void macfdb_read_specific_mac(struct zebra_ns *zns, struct interface *br_if, + struct ethaddr *mac, vlanid_t vid) +{ +} + void neigh_read(struct zebra_ns *zns) { } @@ -269,6 +274,10 @@ void neigh_read_for_vlan(struct zebra_ns *zns, struct interface *vlan_if) { } +void neigh_read_specific_ip(struct ipaddr *ip, struct interface *vlan_if) +{ +} + void kernel_read_pbr_rules(struct zebra_ns *zns) { } diff --git a/zebra/rtread_netlink.c b/zebra/rtread_netlink.c index e99204607..fbca47351 100644 --- a/zebra/rtread_netlink.c +++ b/zebra/rtread_netlink.c @@ -45,6 +45,12 @@ void macfdb_read_for_bridge(struct zebra_ns *zns, struct interface *ifp, netlink_macfdb_read_for_bridge(zns, ifp, br_if); } +void macfdb_read_specific_mac(struct zebra_ns *zns, struct interface *br_if, + struct ethaddr *mac, vlanid_t vid) +{ +netlink_macfdb_read_specific_mac(zns, br_if, mac, vid); +} + void neigh_read(struct zebra_ns *zns) { netlink_neigh_read(zns); @@ -55,6 +61,11 @@ void neigh_read_for_vlan(struct zebra_ns *zns, struct interface *vlan_if) netlink_neigh_read_for_vlan(zns, vlan_if); } +void neigh_read_specific_ip(struct ipaddr *ip, struct interface *vlan_if) +{ + netlink_neigh_read_specific_ip(ip, vlan_if); +} + void kernel_read_pbr_rules(struct zebra_ns *zns) { netlink_rules_read(zns); diff --git a/zebra/rtread_sysctl.c b/zebra/rtread_sysctl.c index f88586a6e..4150092d4 100644 --- a/zebra/rtread_sysctl.c +++ b/zebra/rtread_sysctl.c @@ -88,6 +88,11 @@ void macfdb_read_for_bridge(struct zebra_ns *zns, struct interface *ifp, { } +void macfdb_read_specific_mac(struct zebra_ns *zns, struct interface *br_if, + struct ethaddr *mac, vlanid_t vid) +{ +} + void neigh_read(struct zebra_ns *zns) { } @@ -96,6 +101,10 @@ void neigh_read_for_vlan(struct zebra_ns *zns, struct interface *vlan_if) { } +void neigh_read_specific_ip(struct ipaddr *ip, struct interface *vlan_if) +{ +} + void kernel_read_pbr_rules(struct zebra_ns *zns) { } diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 86a781278..8c44838ad 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -5337,6 +5337,9 @@ static void process_remote_macip_del(vni_t vni, zebra_neigh_t *n = NULL; struct interface *ifp = NULL; struct zebra_if *zif = NULL; + struct zebra_ns *zns; + struct zebra_l2info_vxlan *vxl; + struct zebra_vrf *zvrf; char buf[ETHER_ADDR_STRLEN]; char buf1[INET6_ADDRSTRLEN]; @@ -5360,6 +5363,8 @@ static void process_remote_macip_del(vni_t vni, vni); return; } + zns = zebra_ns_lookup(NS_DEFAULT); + vxl = &zif->l2info.vxl; /* The remote VTEP specified is normally expected to exist, but * it is possible that the peer may delete the VTEP before deleting @@ -5386,9 +5391,10 @@ static void process_remote_macip_del(vni_t vni, if (!mac && !n) return; + zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id); + /* Ignore the delete if this mac is a gateway mac-ip */ - if (mac - && CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL) + if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL) && CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW)) { zlog_warn( "Ignore remote MACIP DEL VNI %u MAC %s%s%s as MAC is already configured as gateway MAC", @@ -5402,6 +5408,23 @@ static void process_remote_macip_del(vni_t vni, /* Uninstall remote neighbor or MAC. */ if (n) { + if (zvrf->dad_freeze && + CHECK_FLAG(n->flags, ZEBRA_NEIGH_DUPLICATE) && + CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE) && + (memcmp(n->emac.octet, macaddr->octet, ETH_ALEN) == 0)) { + struct interface *vlan_if; + + vlan_if = zvni_map_to_svi(vxl->access_vlan, + zif->brslave_info.br_if); + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("%s: IP %s (flags 0x%x intf %s) is remote and duplicate, read kernel for local entry", + __PRETTY_FUNCTION__, + ipaddr2str(ipaddr, buf1, + sizeof(buf1)), n->flags, + vlan_if->name); + neigh_read_specific_ip(ipaddr, vlan_if); + } + /* When the MAC changes for an IP, it is possible the * client may update the new MAC before trying to delete the * "old" neighbor (as these are two different MACIP routes). @@ -5414,6 +5437,25 @@ static void process_remote_macip_del(vni_t vni, zvni_deref_ip2mac(zvni, mac); } } else { + /* DAD: when MAC is freeze state as remote learn event, + * remote mac-ip delete event is received will result in freeze + * entry removal, first fetch kernel for the same entry present + * as LOCAL and reachable, avoid deleting this entry instead + * use kerenel local entry to update during unfreeze time. + */ + if (zvrf->dad_freeze && + CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE) && + CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) { + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("%s: MAC %s (flags 0x%x) is remote and duplicate, read kernel for local entry", + __PRETTY_FUNCTION__, + prefix_mac2str(macaddr, buf, + sizeof(buf)), + mac->flags); + macfdb_read_specific_mac(zns, zif->brslave_info.br_if, + macaddr, vxl->access_vlan); + } + if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) { zvni_process_neigh_on_remote_mac_del(zvni, mac); /* |