-/* Attempts to make 'ml' learn from the fact that a frame from 'src_mac' was
- * just observed arriving from 'src_port' on the given 'vlan'.
- *
- * Returns nonzero if we actually learned something from this, zero if it just
- * confirms what we already knew. The nonzero return value is the tag of flows
- * that now need revalidation.
+/* Provides a bitmap of VLANs which have learning disabled, that is, VLANs on
+ * which all packets are flooded. It takes ownership of the bitmap. Returns
+ * true if the set has changed from the previous value. */
+bool
+mac_learning_set_flood_vlans(struct mac_learning *ml, unsigned long *bitmap)
+{
+ bool ret = (bitmap == NULL
+ ? ml->flood_vlans != NULL
+ : (ml->flood_vlans == NULL
+ || !bitmap_equal(bitmap, ml->flood_vlans, 4096)));
+
+ bitmap_free(ml->flood_vlans);
+ ml->flood_vlans = bitmap;
+
+ return ret;
+}
+
+static bool
+is_learning_vlan(const struct mac_learning *ml, uint16_t vlan)
+{
+ return !(ml->flood_vlans && bitmap_is_set(ml->flood_vlans, vlan));
+}
+
+/* Returns true if 'src_mac' may be learned on 'vlan' for 'ml'.
+ * Returns false if 'ml' is NULL, if src_mac is not valid for learning, or if
+ * 'vlan' is configured on 'ml' to flood all packets. */
+bool
+mac_learning_may_learn(const struct mac_learning *ml,
+ const uint8_t src_mac[ETH_ADDR_LEN], uint16_t vlan)
+{
+ return ml && is_learning_vlan(ml, vlan) && !eth_addr_is_multicast(src_mac);
+}
+
+/* Searches 'ml' for and returns a MAC learning entry for 'src_mac' in 'vlan',
+ * inserting a new entry if necessary. The caller must have already verified,
+ * by calling mac_learning_may_learn(), that 'src_mac' and 'vlan' are
+ * learnable.