diff options
| -rw-r--r-- | zebra/if_netlink.c | 37 | ||||
| -rw-r--r-- | zebra/zebra_l2.c | 38 | ||||
| -rw-r--r-- | zebra/zebra_l2.h | 7 | ||||
| -rw-r--r-- | zebra/zebra_vxlan.c | 93 | ||||
| -rw-r--r-- | zebra/zebra_vxlan.h | 1 |
5 files changed, 125 insertions, 51 deletions
diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index 8c528913e9..acd6697b65 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -1021,7 +1021,8 @@ static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup) if (IS_ZEBRA_IF_BOND(ifp)) zebra_l2if_update_bond(ifp, true); if (IS_ZEBRA_IF_BRIDGE_SLAVE(ifp)) - zebra_l2if_update_bridge_slave(ifp, bridge_ifindex, ns_id); + zebra_l2if_update_bridge_slave(ifp, bridge_ifindex, ns_id, + ZEBRA_BRIDGE_NO_ACTION); else if (IS_ZEBRA_IF_BOND_SLAVE(ifp)) zebra_l2if_update_bond_slave(ifp, bond_ifindex, !!bypass); @@ -1852,9 +1853,9 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) ifp, linkinfo[IFLA_INFO_DATA], 1, link_nsid); if (IS_ZEBRA_IF_BRIDGE_SLAVE(ifp)) - zebra_l2if_update_bridge_slave(ifp, - bridge_ifindex, - ns_id); + zebra_l2if_update_bridge_slave( + ifp, bridge_ifindex, ns_id, + ZEBRA_BRIDGE_NO_ACTION); else if (IS_ZEBRA_IF_BOND_SLAVE(ifp)) zebra_l2if_update_bond_slave(ifp, bond_ifindex, !!bypass); @@ -1878,6 +1879,7 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) if_handle_vrf_change(ifp, vrf_id); } else { bool was_bridge_slave, was_bond_slave; + uint8_t chgflags = ZEBRA_BRIDGE_NO_ACTION; /* Interface update. */ if (IS_ZEBRA_DEBUG_KERNEL) @@ -1919,6 +1921,8 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) if_down(ifp); rib_update(RIB_UPDATE_KERNEL); } else if (if_is_operative(ifp)) { + bool mac_updated = false; + /* Must notify client daemons of new * interface status. */ if (IS_ZEBRA_DEBUG_KERNEL) @@ -1929,9 +1933,11 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) /* Update EVPN VNI when SVI MAC change */ - if (IS_ZEBRA_IF_VLAN(ifp) && - memcmp(old_hw_addr, ifp->hw_addr, - INTERFACE_HWADDR_MAX)) { + if (memcmp(old_hw_addr, ifp->hw_addr, + INTERFACE_HWADDR_MAX)) + mac_updated = true; + if (IS_ZEBRA_IF_VLAN(ifp) + && mac_updated) { struct interface *link_if; link_if = @@ -1941,6 +1947,13 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) if (link_if) zebra_vxlan_svi_up(ifp, link_if); + } else if (mac_updated + && IS_ZEBRA_IF_BRIDGE(ifp)) { + zlog_debug( + "Intf %s(%u) bridge changed MAC address", + name, ifp->ifindex); + chgflags = + ZEBRA_BRIDGE_MASTER_MAC_CHANGE; } } } else { @@ -1951,6 +1964,9 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) "Intf %s(%u) has come UP", name, ifp->ifindex); if_up(ifp); + if (IS_ZEBRA_IF_BRIDGE(ifp)) + chgflags = + ZEBRA_BRIDGE_MASTER_UP; } else { if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug( @@ -1966,12 +1982,13 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) netlink_interface_update_l2info( ifp, linkinfo[IFLA_INFO_DATA], 0, link_nsid); + if (IS_ZEBRA_IF_BRIDGE(ifp)) + zebra_l2if_update_bridge(ifp, chgflags); if (IS_ZEBRA_IF_BOND(ifp)) zebra_l2if_update_bond(ifp, true); if (IS_ZEBRA_IF_BRIDGE_SLAVE(ifp) || was_bridge_slave) - zebra_l2if_update_bridge_slave(ifp, - bridge_ifindex, - ns_id); + zebra_l2if_update_bridge_slave( + ifp, bridge_ifindex, ns_id, chgflags); else if (IS_ZEBRA_IF_BOND_SLAVE(ifp) || was_bond_slave) zebra_l2if_update_bond_slave(ifp, bond_ifindex, !!bypass); diff --git a/zebra/zebra_l2.c b/zebra/zebra_l2.c index 71fac556e1..5a02149611 100644 --- a/zebra/zebra_l2.c +++ b/zebra/zebra_l2.c @@ -50,7 +50,8 @@ /* static function declarations */ /* Private functions */ -static void map_slaves_to_bridge(struct interface *br_if, int link) +static void map_slaves_to_bridge(struct interface *br_if, int link, + bool update_slave, uint8_t chgflags) { struct vrf *vrf; struct interface *ifp; @@ -79,9 +80,17 @@ static void map_slaves_to_bridge(struct interface *br_if, int link) br_slave = &zif->brslave_info; if (link) { - if (br_slave->bridge_ifindex == br_if->ifindex && - br_slave->ns_id == zns->ns_id) + if (br_slave->bridge_ifindex == br_if->ifindex + && br_slave->ns_id == zns->ns_id) { br_slave->br_if = br_if; + if (update_slave) { + zebra_l2if_update_bridge_slave( + ifp, + br_slave->bridge_ifindex, + br_slave->ns_id, + chgflags); + } + } } else { if (br_slave->br_if == br_if) br_slave->br_if = NULL; @@ -261,7 +270,7 @@ void zebra_l2_bridge_add_update(struct interface *ifp, memcpy(&zif->l2info.br, bridge_info, sizeof(*bridge_info)); /* Link all slaves to this bridge */ - map_slaves_to_bridge(ifp, 1); + map_slaves_to_bridge(ifp, 1, false, ZEBRA_BRIDGE_NO_ACTION); } /* @@ -270,7 +279,14 @@ void zebra_l2_bridge_add_update(struct interface *ifp, void zebra_l2_bridge_del(struct interface *ifp) { /* Unlink all slaves to this bridge */ - map_slaves_to_bridge(ifp, 0); + map_slaves_to_bridge(ifp, 0, false, ZEBRA_BRIDGE_NO_ACTION); +} + +void zebra_l2if_update_bridge(struct interface *ifp, uint8_t chgflags) +{ + if (!chgflags) + return; + map_slaves_to_bridge(ifp, 1, true, chgflags); } /* @@ -398,8 +414,8 @@ void zebra_l2_vxlanif_del(struct interface *ifp) * from a bridge before it can be mapped to another bridge. */ void zebra_l2if_update_bridge_slave(struct interface *ifp, - ifindex_t bridge_ifindex, - ns_id_t ns_id) + ifindex_t bridge_ifindex, ns_id_t ns_id, + uint8_t chgflags) { struct zebra_if *zif; ifindex_t old_bridge_ifindex; @@ -413,6 +429,14 @@ void zebra_l2if_update_bridge_slave(struct interface *ifp, if (!zvrf) return; + if (zif->zif_type == ZEBRA_IF_VXLAN + && chgflags != ZEBRA_BRIDGE_NO_ACTION) { + if (ZEBRA_BRIDGE_MASTER_MAC_CHANGE) + zebra_vxlan_if_update(ifp, + ZEBRA_VXLIF_MASTER_MAC_CHANGE); + if (ZEBRA_BRIDGE_MASTER_UP) + zebra_vxlan_if_update(ifp, ZEBRA_VXLIF_MASTER_CHANGE); + } old_bridge_ifindex = zif->brslave_info.bridge_ifindex; old_ns_id = zif->brslave_info.ns_id; if (old_bridge_ifindex == bridge_ifindex && diff --git a/zebra/zebra_l2.h b/zebra/zebra_l2.h index 6572f344c4..98744f3c1f 100644 --- a/zebra/zebra_l2.h +++ b/zebra/zebra_l2.h @@ -33,6 +33,10 @@ extern "C" { #endif +#define ZEBRA_BRIDGE_NO_ACTION (0) +#define ZEBRA_BRIDGE_MASTER_MAC_CHANGE (1 << 1) +#define ZEBRA_BRIDGE_MASTER_UP (1 << 2) + /* zebra L2 interface information - bridge slave (linkage to bridge) */ struct zebra_l2info_brslave { ifindex_t bridge_ifindex; /* Bridge Master */ @@ -121,7 +125,7 @@ extern void zebra_l2_greif_del(struct interface *ifp); extern void zebra_l2_vxlanif_del(struct interface *ifp); extern void zebra_l2if_update_bridge_slave(struct interface *ifp, ifindex_t bridge_ifindex, - ns_id_t ns_id); + ns_id_t ns_id, uint8_t chgflags); extern void zebra_l2if_update_bond_slave(struct interface *ifp, ifindex_t bond_ifindex, bool bypass); @@ -130,6 +134,7 @@ extern void zebra_vlan_bitmap_compute(struct interface *ifp, extern void zebra_vlan_mbr_re_eval(struct interface *ifp, bitfield_t vlan_bitmap); extern void zebra_l2if_update_bond(struct interface *ifp, bool add); +extern void zebra_l2if_update_bridge(struct interface *ifp, uint8_t chgflags); #ifdef __cplusplus } diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index aede4098b4..c13c867d2a 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -1798,6 +1798,51 @@ struct zebra_l3vni *zl3vni_from_vrf(vrf_id_t vrf_id) return zl3vni_lookup(zvrf->l3vni); } +static int zl3vni_from_svi_ns(struct ns *ns, void *_in_param, void **_p_zl3vni) +{ + int found = 0; + struct zebra_ns *zns = ns->info; + struct zebra_l3vni **p_zl3vni = (struct zebra_l3vni **)_p_zl3vni; + struct zebra_from_svi_param *in_param = + (struct zebra_from_svi_param *)_in_param; + struct route_node *rn = NULL; + struct interface *tmp_if = NULL; + struct zebra_if *zif = NULL; + struct zebra_l2info_vxlan *vxl = NULL; + + if (!in_param) + return NS_WALK_STOP; + + /* loop through all vxlan-interface */ + for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) { + tmp_if = (struct interface *)rn->info; + if (!tmp_if) + continue; + zif = tmp_if->info; + if (!zif || zif->zif_type != ZEBRA_IF_VXLAN) + continue; + if (!if_is_operative(tmp_if)) + continue; + vxl = &zif->l2info.vxl; + + if (zif->brslave_info.br_if != in_param->br_if) + continue; + + if (!in_param->bridge_vlan_aware + || vxl->access_vlan == in_param->vid) { + found = 1; + break; + } + } + + if (!found) + return NS_WALK_CONTINUE; + + if (p_zl3vni) + *p_zl3vni = zl3vni_lookup(vxl->vni); + return NS_WALK_STOP; +} + /* * Map SVI and associated bridge to a VNI. This is invoked upon getting * neighbor notifications, to see if they are of interest. @@ -1805,16 +1850,11 @@ struct zebra_l3vni *zl3vni_from_vrf(vrf_id_t vrf_id) static struct zebra_l3vni *zl3vni_from_svi(struct interface *ifp, struct interface *br_if) { - int found = 0; - vlanid_t vid = 0; - uint8_t bridge_vlan_aware = 0; struct zebra_l3vni *zl3vni = NULL; - struct zebra_ns *zns = NULL; - struct route_node *rn = NULL; struct zebra_if *zif = NULL; - struct interface *tmp_if = NULL; struct zebra_l2info_bridge *br = NULL; - struct zebra_l2info_vxlan *vxl = NULL; + struct zebra_from_svi_param in_param = {}; + struct zebra_l3vni **p_zl3vni; if (!br_if) return NULL; @@ -1822,13 +1862,14 @@ static struct zebra_l3vni *zl3vni_from_svi(struct interface *ifp, /* Make sure the linked interface is a bridge. */ if (!IS_ZEBRA_IF_BRIDGE(br_if)) return NULL; + in_param.br_if = br_if; /* Determine if bridge is VLAN-aware or not */ zif = br_if->info; assert(zif); br = &zif->l2info.br; - bridge_vlan_aware = br->vlan_aware; - if (bridge_vlan_aware) { + in_param.bridge_vlan_aware = br->vlan_aware; + if (in_param.bridge_vlan_aware) { struct zebra_l2info_vlan *vl; if (!IS_ZEBRA_IF_VLAN(ifp)) @@ -1837,36 +1878,15 @@ static struct zebra_l3vni *zl3vni_from_svi(struct interface *ifp, zif = ifp->info; assert(zif); vl = &zif->l2info.vl; - vid = vl->vid; + in_param.vid = vl->vid; } /* See if this interface (or interface plus VLAN Id) maps to a VxLAN */ /* TODO: Optimize with a hash. */ - zns = zebra_ns_lookup(NS_DEFAULT); - for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) { - tmp_if = (struct interface *)rn->info; - if (!tmp_if) - continue; - zif = tmp_if->info; - if (!zif || zif->zif_type != ZEBRA_IF_VXLAN) - continue; - if (!if_is_operative(tmp_if)) - continue; - vxl = &zif->l2info.vxl; - - if (zif->brslave_info.br_if != br_if) - continue; - if (!bridge_vlan_aware || vxl->access_vlan == vid) { - found = 1; - break; - } - } + p_zl3vni = &zl3vni; - if (!found) - return NULL; - - zl3vni = zl3vni_lookup(vxl->vni); + ns_walk_func(zl3vni_from_svi_ns, (void *)&in_param, (void **)p_zl3vni); return zl3vni; } @@ -5023,6 +5043,13 @@ int zebra_vxlan_if_update(struct interface *ifp, uint16_t chgflags) return 0; } + if ((chgflags & ZEBRA_VXLIF_MASTER_MAC_CHANGE) + && if_is_operative(ifp) && is_l3vni_oper_up(zl3vni)) { + zebra_vxlan_process_l3vni_oper_down(zl3vni); + zebra_vxlan_process_l3vni_oper_up(zl3vni); + return 0; + } + /* access-vlan change - process oper down, associate with new * svi_if and then process oper up again */ diff --git a/zebra/zebra_vxlan.h b/zebra/zebra_vxlan.h index 915e987b6b..464a8e5fc4 100644 --- a/zebra/zebra_vxlan.h +++ b/zebra/zebra_vxlan.h @@ -65,6 +65,7 @@ is_vxlan_flooding_head_end(void) #define ZEBRA_VXLIF_MASTER_CHANGE (1 << 1) #define ZEBRA_VXLIF_VLAN_CHANGE (1 << 2) #define ZEBRA_VXLIF_MCAST_GRP_CHANGE (1 << 3) +#define ZEBRA_VXLIF_MASTER_MAC_CHANGE (1 << 4) #define VNI_STR_LEN 32 |
