+static void
+map_insert_ipdev(struct ip_device *ip_dev)
+{
+ struct tnl_port *p;
+
+ LIST_FOR_EACH(p, node, &port_list) {
+ map_insert(p->port, ip_dev->mac, ip_dev->addr,
+ p->udp_port, p->dev_name);
+ }
+}
+
+static void
+insert_ipdev(const char dev_name[])
+{
+ struct ip_device *ip_dev;
+ enum netdev_flags flags;
+ struct netdev *dev;
+ int error;
+
+ error = netdev_open(dev_name, NULL, &dev);
+ if (error) {
+ return;
+ }
+
+ error = netdev_get_flags(dev, &flags);
+ if (error || (flags & NETDEV_LOOPBACK)) {
+ netdev_close(dev);
+ return;
+ }
+
+ ip_dev = xzalloc(sizeof *ip_dev);
+ ip_dev->dev = dev;
+ ip_dev->change_seq = netdev_get_change_seq(dev);
+ error = netdev_get_etheraddr(ip_dev->dev, &ip_dev->mac);
+ if (error) {
+ return;
+ }
+ error = netdev_get_in4(ip_dev->dev, (struct in_addr *)&ip_dev->addr, NULL);
+ if (error) {
+ return;
+ }
+ ovs_strlcpy(ip_dev->dev_name, netdev_get_name(dev), sizeof ip_dev->dev_name);
+
+ list_insert(&addr_list, &ip_dev->node);
+ map_insert_ipdev(ip_dev);
+}
+
+static void
+delete_ipdev(struct ip_device *ip_dev)
+{
+ struct tnl_port *p;
+
+ LIST_FOR_EACH(p, node, &port_list) {
+ map_delete(ip_dev->mac, ip_dev->addr, p->udp_port);
+ }
+
+ list_remove(&ip_dev->node);
+ netdev_close(ip_dev->dev);
+ free(ip_dev);
+}
+
+void
+tnl_port_map_insert_ipdev(const char dev_name[])
+{
+ struct ip_device *ip_dev;
+
+ ovs_mutex_lock(&mutex);
+
+ LIST_FOR_EACH(ip_dev, node, &addr_list) {
+ if (!strcmp(netdev_get_name(ip_dev->dev), dev_name)) {
+ if (ip_dev->change_seq == netdev_get_change_seq(ip_dev->dev)) {
+ goto out;
+ }
+ /* Address changed. */
+ delete_ipdev(ip_dev);
+ break;
+ }
+ }
+ insert_ipdev(dev_name);
+
+out:
+ ovs_mutex_unlock(&mutex);
+}
+
+void
+tnl_port_map_delete_ipdev(const char dev_name[])
+{
+ struct ip_device *ip_dev, *next;
+
+ ovs_mutex_lock(&mutex);
+ LIST_FOR_EACH_SAFE(ip_dev, next, node, &addr_list) {
+ if (!strcmp(netdev_get_name(ip_dev->dev), dev_name)) {
+ delete_ipdev(ip_dev);
+ }
+ }
+ ovs_mutex_unlock(&mutex);
+}
+
+void
+tnl_port_map_run(void)
+{
+ struct ip_device *ip_dev;
+
+ ovs_mutex_lock(&mutex);
+ LIST_FOR_EACH(ip_dev, node, &addr_list) {
+ char dev_name[IFNAMSIZ];
+
+ if (ip_dev->change_seq == netdev_get_change_seq(ip_dev->dev)) {
+ continue;
+ }
+
+ /* Address changed. */
+ ovs_strlcpy(dev_name, ip_dev->dev_name, sizeof dev_name);
+ delete_ipdev(ip_dev);
+ insert_ipdev(dev_name);
+ }
+ ovs_mutex_unlock(&mutex);
+}
+