예제 #1
0
static int rule_compare(struct nl_object *_a, struct nl_object *_b,
			uint32_t attrs, int flags)
{
	struct rtnl_rule *a = (struct rtnl_rule *) _a;
	struct rtnl_rule *b = (struct rtnl_rule *) _b;
	int diff = 0;

#define RULE_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, RULE_ATTR_##ATTR, a, b, EXPR)

	diff |= RULE_DIFF(FAMILY,	a->r_family != b->r_family);
	diff |= RULE_DIFF(TABLE,	a->r_table != b->r_table);
	diff |= RULE_DIFF(REALMS,	a->r_realms != b->r_realms);
	diff |= RULE_DIFF(DSFIELD,	a->r_dsfield != b->r_dsfield);
	diff |= RULE_DIFF(TYPE,		a->r_type != b->r_type);
	diff |= RULE_DIFF(PRIO,		a->r_prio != b->r_prio);
	diff |= RULE_DIFF(MARK,		a->r_mark != b->r_mark);
	diff |= RULE_DIFF(SRC_LEN,	a->r_src_len != b->r_src_len);
	diff |= RULE_DIFF(DST_LEN,	a->r_dst_len != b->r_dst_len);
	diff |= RULE_DIFF(SRC,		nl_addr_cmp(a->r_src, b->r_src));
	diff |= RULE_DIFF(DST,		nl_addr_cmp(a->r_dst, b->r_dst));
	diff |= RULE_DIFF(IIF,		strcmp(a->r_iif, b->r_iif));
	
#undef RULE_DIFF

	return diff;
}
예제 #2
0
static int rule_compare(struct nl_object *_a, struct nl_object *_b,
			uint32_t attrs, int flags)
{
	struct rtnl_rule *a = (struct rtnl_rule *) _a;
	struct rtnl_rule *b = (struct rtnl_rule *) _b;
	int diff = 0;

#define RULE_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, RULE_ATTR_##ATTR, a, b, EXPR)

	diff |= RULE_DIFF(FAMILY,	a->r_family != b->r_family);
	diff |= RULE_DIFF(TABLE,	a->r_table != b->r_table);
	diff |= RULE_DIFF(ACTION,	a->r_action != b->r_action);
	diff |= RULE_DIFF(IIFNAME,	strcmp(a->r_iifname, b->r_iifname));
	diff |= RULE_DIFF(OIFNAME,	strcmp(a->r_oifname, b->r_oifname));
	diff |= RULE_DIFF(PRIO,		a->r_prio != b->r_prio);
	diff |= RULE_DIFF(MARK,		a->r_mark != b->r_mark);
	diff |= RULE_DIFF(MASK,		a->r_mask != b->r_mask);
	diff |= RULE_DIFF(GOTO,		a->r_goto != b->r_goto);
	diff |= RULE_DIFF(SRC,		nl_addr_cmp(a->r_src, b->r_src));
	diff |= RULE_DIFF(DST,		nl_addr_cmp(a->r_dst, b->r_dst));
	diff |= RULE_DIFF(DSFIELD,	a->r_dsfield != b->r_dsfield);
	diff |= RULE_DIFF(FLOW,		a->r_flow != b->r_flow);
	
#undef RULE_DIFF

	return diff;
}
예제 #3
0
파일: addr.c 프로젝트: artisdom/mipv6
static int addr_filter(struct nl_object *obj, struct nl_object *filter)
{
	struct rtnl_addr *o = (struct rtnl_addr *) obj;
	struct rtnl_addr *f = (struct rtnl_addr *) filter;

#define REQ(F) (f->a_mask & ADDR_ATTR_##F)
#define AVAIL(F) (o->a_mask & ADDR_ATTR_##F)
#define _O(F, EXPR) (REQ(F) && (!AVAIL(F) || (EXPR)))
#define _C(F, N) (REQ(F) && (!AVAIL(F) || (o->N != f->N)))
	if (_C(IFINDEX,	   a_ifindex)					||
	    _C(FAMILY,	   a_family)					||
	    _C(SCOPE,	   a_scope)					||
	    _O(FLAGS,	   f->a_flags ^ (o->a_flags & f->a_flag_mask))	||
	    _O(LABEL,	   strcmp(o->a_label, f->a_label))		||
	    _O(PEER, 	   nl_addr_cmp(o->a_peer, f->a_peer))		||
	    _O(LOCAL,	   nl_addr_cmp(o->a_local, f->a_local))		||
	    _O(ANYCAST,	   nl_addr_cmp(o->a_anycast, f->a_anycast))	||
	    _O(MULTICAST,  nl_addr_cmp(o->a_multicast, f->a_multicast))	||
	    _O(BROADCAST,  nl_addr_cmp(o->a_bcast, f->a_bcast)))
		return 0;
#undef REQ
#undef AVAIL
#undef _O
#undef _C

	return 1;
}
static int addr_compare(struct nl_object *_a, struct nl_object *_b,
			uint32_t attrs, int flags)
{
	struct rtnl_addr *a = (struct rtnl_addr *) _a;
	struct rtnl_addr *b = (struct rtnl_addr *) _b;
	int diff = 0;

#define ADDR_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, ADDR_ATTR_##ATTR, a, b, EXPR)

	diff |= ADDR_DIFF(IFINDEX,	a->a_ifindex != b->a_ifindex);
	diff |= ADDR_DIFF(FAMILY,	a->a_family != b->a_family);
	diff |= ADDR_DIFF(SCOPE,	a->a_scope != b->a_scope);
	diff |= ADDR_DIFF(LABEL,	strcmp(a->a_label, b->a_label));
	diff |= ADDR_DIFF(PEER,		nl_addr_cmp(a->a_peer, b->a_peer));
	diff |= ADDR_DIFF(LOCAL,	nl_addr_cmp(a->a_local, b->a_local));
	diff |= ADDR_DIFF(ANYCAST,	nl_addr_cmp(a->a_anycast,b->a_anycast));
	diff |= ADDR_DIFF(MULTICAST,	nl_addr_cmp(a->a_multicast,
						    b->a_multicast));
	diff |= ADDR_DIFF(BROADCAST,	nl_addr_cmp(a->a_bcast, b->a_bcast));

	if (flags & LOOSE_FLAG_COMPARISON)
		diff |= ADDR_DIFF(FLAGS,
				  (a->a_flags ^ b->a_flags) & b->a_flag_mask);
	else
		diff |= ADDR_DIFF(FLAGS, a->a_flags != b->a_flags);

#undef ADDR_DIFF

	return diff;
}
예제 #5
0
파일: ae.c 프로젝트: Domikk/libnl
static uint64_t xfrm_ae_compare(struct nl_object *_a, struct nl_object *_b,
				uint64_t attrs, int flags)
{
	struct xfrmnl_ae* a  =   (struct xfrmnl_ae *) _a;
	struct xfrmnl_ae* b  =   (struct xfrmnl_ae *) _b;
	uint64_t diff = 0;
	int found = 0;

#define XFRM_AE_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, XFRM_AE_ATTR_##ATTR, a, b, EXPR)
	diff |= XFRM_AE_DIFF(DADDR,	nl_addr_cmp(a->sa_id.daddr, b->sa_id.daddr));
	diff |= XFRM_AE_DIFF(SPI,	a->sa_id.spi != b->sa_id.spi);
	diff |= XFRM_AE_DIFF(PROTO,	a->sa_id.proto != b->sa_id.proto);
	diff |= XFRM_AE_DIFF(SADDR,	nl_addr_cmp(a->saddr, b->saddr));
	diff |= XFRM_AE_DIFF(FLAGS, a->flags != b->flags);
	diff |= XFRM_AE_DIFF(REQID, a->reqid != b->reqid);
	diff |= XFRM_AE_DIFF(MARK, (a->mark.v & a->mark.m) != (b->mark.v & b->mark.m));
	diff |= XFRM_AE_DIFF(REPLAY_MAXAGE, a->replay_maxage != b->replay_maxage);
	diff |= XFRM_AE_DIFF(REPLAY_MAXDIFF, a->replay_maxdiff != b->replay_maxdiff);

	/* Compare replay states */
	found = AVAILABLE_MISMATCH (a, b, XFRM_AE_ATTR_REPLAY_STATE);
	if (found == 0) // attribute exists in both objects
	{
		if (((a->replay_state_esn != NULL) && (b->replay_state_esn == NULL)) ||
			((a->replay_state_esn == NULL) && (b->replay_state_esn != NULL)))
			found |= 1;

		if (found == 0) // same replay type. compare actual values
		{
			if (a->replay_state_esn)
			{
				if (a->replay_state_esn->bmp_len != b->replay_state_esn->bmp_len)
					diff |= 1;
				else
				{
					uint32_t len = sizeof (struct xfrmnl_replay_state_esn) + (sizeof (uint32_t) * a->replay_state_esn->bmp_len);
					diff |= memcmp (a->replay_state_esn, b->replay_state_esn, len);
				}
			}
			else
			{
				if ((a->replay_state.oseq != b->replay_state.oseq) ||
				    (a->replay_state.seq != b->replay_state.seq) ||
				    (a->replay_state.bitmap != b->replay_state.bitmap))
					diff |= 1;
			}
		}
	}
#undef XFRM_AE_DIFF

	return diff;
}
예제 #6
0
static gint
_j4status_nl_address_compare(gconstpointer a, gconstpointer b)
{
    if ( a == b )
        return 0;
    return nl_addr_cmp(a, b);
}
static void change_cb(struct nl_cache *cache, struct nl_object *obj,
		      int action)
{
	struct nfnl_ct *ct = (struct nfnl_ct *) obj;
	static struct nl_addr *hack = NULL;

	if (!hack)
		hack = nl_addr_parse("194.88.212.233", AF_INET);

	if (!nl_addr_cmp(hack, nfnl_ct_get_src(ct, 1)) ||
	    !nl_addr_cmp(hack, nfnl_ct_get_dst(ct, 1))) {
		struct nl_dump_params dp = {
			.dp_type = NL_DUMP_LINE,
			.dp_fd = stdout,
		};

		printf("UPDATE ");
		nl_object_dump(obj, &dp);
	}
}
예제 #8
0
파일: ct_obj.c 프로젝트: Distrotech/libnl
static void ct_dump_tuples(struct nfnl_ct *ct, struct nl_dump_params *p)
{
	struct nl_addr *orig_src, *orig_dst, *reply_src, *reply_dst;
	int orig_sport = 0, orig_dport = 0, reply_sport = 0, reply_dport = 0;
	int sync = 0;

	orig_src = nfnl_ct_get_src(ct, 0);
	orig_dst = nfnl_ct_get_dst(ct, 0);
	reply_src = nfnl_ct_get_src(ct, 1);
	reply_dst = nfnl_ct_get_dst(ct, 1);

	if (nfnl_ct_test_src_port(ct, 0))
		orig_sport = nfnl_ct_get_src_port(ct, 0);

	if (nfnl_ct_test_dst_port(ct, 0))
		orig_dport = nfnl_ct_get_dst_port(ct, 0);

	if (nfnl_ct_test_src_port(ct, 1))
		reply_sport = nfnl_ct_get_src_port(ct, 1);

	if (nfnl_ct_test_dst_port(ct, 1))
		reply_dport = nfnl_ct_get_dst_port(ct, 1);

	if (orig_src && orig_dst && reply_src && reply_dst &&
	    orig_sport == reply_dport && orig_dport == reply_sport &&
	    !nl_addr_cmp(orig_src, reply_dst) &&
	    !nl_addr_cmp(orig_dst, reply_src))
		sync = 1;

	dump_addr(p, orig_src, orig_sport);
	nl_dump(p, sync ? "<-> " : "-> ");
	dump_addr(p, orig_dst, orig_dport);
	dump_icmp(p, ct, 0);

	if (!sync) {
		dump_addr(p, reply_src, reply_sport);
		nl_dump(p, "<- ");
		dump_addr(p, reply_dst, reply_dport);
		dump_icmp(p, ct, 1);
	}
}
예제 #9
0
/* Given an interface's MAC address, return the name (e.g., eth0) in human
 * readable format.  Return NULL for no match
 */
char *iface_mac2device(char *mac) {
    struct nl_handle *handle = NULL;
    struct nl_cache *cache = NULL;
    struct rtnl_link *link = NULL;
    struct nl_addr *mac_as_nl_addr = NULL;
    char *retval = NULL;
    int i, n;

    if (mac == NULL) {
        return NULL;
    }

    if ((mac_as_nl_addr = nl_addr_parse(mac, AF_LLC)) == NULL) {
        return NULL;
    }

    if ((cache = _iface_get_link_cache(&handle)) == NULL) {
        return NULL;
    }

    n = nl_cache_nitems(cache);
    for (i = 0; i <= n; i++) {
        struct nl_addr *addr;

        if ((link = rtnl_link_get(cache, i)) == NULL) {
            continue;
        }

        addr = rtnl_link_get_addr(link);

        if (!nl_addr_cmp(mac_as_nl_addr, addr)) {
            retval = strdup(rtnl_link_get_name(link));
            rtnl_link_put(link);
            break;
        }

        rtnl_link_put(link);
    }

    nl_close(handle);
    nl_handle_destroy(handle);

    return retval;
}
예제 #10
0
static int request_compare(struct nl_object *_a, struct nl_object *_b,
			   uint32_t attrs, int flags)
{
	struct flnl_request *a = (struct flnl_request *) _a;
	struct flnl_request *b = (struct flnl_request *) _b;
	int diff = 0;

#define REQ_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, REQUEST_ATTR_##ATTR, a, b, EXPR)

	diff |= REQ_DIFF(FWMARK,	a->lr_fwmark != b->lr_fwmark);
	diff |= REQ_DIFF(TOS,		a->lr_tos != b->lr_tos);
	diff |= REQ_DIFF(SCOPE,		a->lr_scope != b->lr_scope);
	diff |= REQ_DIFF(TABLE,		a->lr_table != b->lr_table);
	diff |= REQ_DIFF(ADDR,		nl_addr_cmp(a->lr_addr, b->lr_addr));

#undef REQ_DIFF

	return diff;
}
예제 #11
0
int rtnl_route_nh_compare(struct rtnl_nexthop *a, struct rtnl_nexthop *b,
			  uint32_t attrs, int loose)
{
	int diff = 0;

#define NH_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, NH_ATTR_##ATTR, a, b, EXPR)

	diff |= NH_DIFF(IFINDEX,	a->rtnh_ifindex != b->rtnh_ifindex);
	diff |= NH_DIFF(WEIGHT,		a->rtnh_weight != b->rtnh_weight);
	diff |= NH_DIFF(REALMS,		a->rtnh_realms != b->rtnh_realms);
	diff |= NH_DIFF(GATEWAY,	nl_addr_cmp(a->rtnh_gateway,
						    b->rtnh_gateway));

	if (loose)
		diff |= NH_DIFF(FLAGS,
			  (a->rtnh_flags ^ b->rtnh_flags) & b->rtnh_flag_mask);
	else
		diff |= NH_DIFF(FLAGS, a->rtnh_flags != b->rtnh_flags);
	
#undef NH_DIFF

	return diff;
}
예제 #12
0
void nl_bridge::remove_neigh_from_fdb(rtnl_neigh *neigh) {
  assert(sw);
  nl_addr *addr = rtnl_neigh_get_lladdr(neigh);

  if (nl_addr_cmp(rtnl_link_get_addr(bridge), addr) == 0) {
    // ignore ll addr of bridge on slave
    return;
  }

  // lookup l2_cache as well
  std::unique_ptr<rtnl_neigh, decltype(&rtnl_neigh_put)> n_lookup(
      NEIGH_CAST(nl_cache_search(l2_cache.get(), OBJ_CAST(neigh))),
      rtnl_neigh_put);

  if (n_lookup) {
    nl_cache_remove(OBJ_CAST(n_lookup.get()));
  }

  const uint32_t port = nl->get_port_id(rtnl_neigh_get_ifindex(neigh));
  rofl::caddress_ll mac((uint8_t *)nl_addr_get_binary_addr(addr),
                        nl_addr_get_len(addr));

  sw->l2_addr_remove(port, rtnl_neigh_get_vlan(neigh), mac);
}
예제 #13
0
파일: addr.c 프로젝트: artisdom/mipv6
static int addr_msg_parser(struct sockaddr_nl *who, struct nlmsghdr *nlh,
			   void *arg)
{
	struct rtnl_addr *addr;
	struct nl_parser_param *pp = arg;
	struct ifaddrmsg *ifa;
	struct nlattr *tb[IFA_MAX+1];
	int err = -ENOMEM, peer_prefix = 0;

	addr = rtnl_addr_alloc();
	if (!addr) {
		err = nl_errno(ENOMEM);
		goto errout;
	}
	addr->ce_msgtype = nlh->nlmsg_type;

	err = nlmsg_parse(nlh, sizeof(*ifa), tb, IFA_MAX, addr_policy);
	if (err < 0)
		goto errout_free;

	ifa = nlmsg_data(nlh);
	addr->a_family = ifa->ifa_family;
	addr->a_prefixlen = ifa->ifa_prefixlen;
	addr->a_flags = ifa->ifa_flags;
	addr->a_scope = ifa->ifa_scope;
	addr->a_ifindex = ifa->ifa_index;

	addr->a_mask = (ADDR_ATTR_FAMILY | ADDR_ATTR_PREFIXLEN |
			ADDR_ATTR_FLAGS | ADDR_ATTR_SCOPE | ADDR_ATTR_IFINDEX);

	if (tb[IFA_LABEL]) {
		nla_strlcpy(addr->a_label, tb[IFA_LABEL], IFNAMSIZ);
		addr->a_mask |= ADDR_ATTR_LABEL;
	}

	if (tb[IFA_CACHEINFO]) {
		struct ifa_cacheinfo *ca;
		
		ca = nla_data(tb[IFA_CACHEINFO]);
		addr->a_cacheinfo.aci_prefered = ca->ifa_prefered;
		addr->a_cacheinfo.aci_valid = ca->ifa_valid;
		addr->a_cacheinfo.aci_cstamp = ca->cstamp;
		addr->a_cacheinfo.aci_tstamp = ca->tstamp;
		addr->a_mask |= ADDR_ATTR_CACHEINFO;
	}

	if (tb[IFA_LOCAL]) {
		addr->a_local = nla_get_addr(tb[IFA_LOCAL], addr->a_family);
		if (!addr->a_local)
			goto errout_free;
		addr->a_mask |= ADDR_ATTR_LOCAL;
	}

	if (tb[IFA_ADDRESS]) {
		struct nl_addr *a;

		a = nla_get_addr(tb[IFA_ADDRESS], addr->a_family);
		if (!a)
			goto errout_free;

		/* IPv6 sends the local address as IFA_ADDRESS with
		 * no IFA_LOCAL, IPv4 sends both IFA_LOCAL and IFA_ADDRESS
		 * with IFA_ADDRESS being the peer address if they differ */
		if (!tb[IFA_LOCAL] || !nl_addr_cmp(a, addr->a_local)) {
			nl_addr_put(addr->a_local);
			addr->a_local = a;
			addr->a_mask |= ADDR_ATTR_LOCAL;
		} else {
			addr->a_peer = a;
			addr->a_mask |= ADDR_ATTR_PEER;
			peer_prefix = 1;
		}
	}

	nl_addr_set_prefixlen(peer_prefix ? addr->a_peer : addr->a_local,
			      addr->a_prefixlen);

	if (tb[IFA_BROADCAST]) {
		addr->a_bcast = nla_get_addr(tb[IFA_BROADCAST], addr->a_family);
		if (!addr->a_bcast)
			goto errout_free;

		addr->a_mask |= ADDR_ATTR_BROADCAST;
	}

	if (tb[IFA_ANYCAST]) {
		addr->a_anycast = nla_get_addr(tb[IFA_ANYCAST], addr->a_family);
		if (!addr->a_anycast)
			goto errout_free;

		addr->a_mask |= ADDR_ATTR_ANYCAST;
	}

	if (tb[IFA_MULTICAST]) {
		addr->a_multicast = nla_get_addr(tb[IFA_MULTICAST],
						 addr->a_family);
		if (!addr->a_multicast)
			goto errout_free;

		addr->a_mask |= ADDR_ATTR_MULTICAST;
	}

	err = pp->pp_cb((struct nl_object *) addr, pp);
	if (err < 0)
		goto errout_free;

	return P_ACCEPT;

errout_free:
	rtnl_addr_free(addr);
errout:
	return err;
}
예제 #14
0
파일: addr.c 프로젝트: artisdom/mipv6
struct rtnl_addr *rtnl_addr_alloc_from_msg(struct nl_msg *msg)
{
	struct nlattr *tb[IFA_MAX+1];
	struct rtnl_addr *addr;
	struct ifaddrmsg *ifa;
	struct nlmsghdr *nlh;
	int err, peer_prefix = 0;

	nlh = nlmsg_hdr(msg);

	addr = rtnl_addr_alloc();
	if (!addr)
		goto errout;

	err = nlmsg_parse(nlh, sizeof(*ifa), tb, IFA_MAX, addr_policy);
	if (err < 0)
		goto errout_free;

	ifa = nlmsg_data(nlh);
	addr->a_family = ifa->ifa_family;
	addr->a_prefixlen = ifa->ifa_prefixlen;
	addr->a_flags = ifa->ifa_flags;
	addr->a_scope = ifa->ifa_scope;
	addr->a_ifindex = ifa->ifa_index;

	addr->a_mask = (ADDR_ATTR_FAMILY | ADDR_ATTR_PREFIXLEN |
			ADDR_ATTR_FLAGS | ADDR_ATTR_SCOPE | ADDR_ATTR_IFINDEX);

	if (tb[IFA_LABEL]) {
		nla_strlcpy(addr->a_label, tb[IFA_LABEL], IFNAMSIZ);
		addr->a_mask |= ADDR_ATTR_LABEL;
	}

	if (tb[IFA_CACHEINFO]) {
		struct ifa_cacheinfo *ca;

		ca = nla_data(tb[IFA_CACHEINFO]);
		addr->a_cacheinfo.aci_prefered = ca->ifa_prefered;
		addr->a_cacheinfo.aci_valid = ca->ifa_valid;
		addr->a_cacheinfo.aci_cstamp = ca->cstamp;
		addr->a_cacheinfo.aci_tstamp = ca->tstamp;
		addr->a_mask |= ADDR_ATTR_CACHEINFO;
	}

	if (tb[IFA_LOCAL]) {
		addr->a_local = nla_get_addr(tb[IFA_LOCAL], addr->a_family);
		if (!addr->a_local)
			goto errout_free;
		addr->a_mask |= ADDR_ATTR_LOCAL;
	}

	if (tb[IFA_ADDRESS]) {
		struct nl_addr *a;

		a = nla_get_addr(tb[IFA_ADDRESS], addr->a_family);
		if (!a)
			goto errout_free;

		/* IPv6 sends the local address as IFA_ADDRESS with
		 * no IFA_LOCAL, IPv4 sends both IFA_LOCAL and IFA_ADDRESS
		 * with IFA_ADDRESS being the peer address if they differ */
		if (!tb[IFA_LOCAL] || !nl_addr_cmp(a, addr->a_local)) {
			addr->a_local = a;
			addr->a_mask |= ADDR_ATTR_LOCAL;
		} else {
			addr->a_peer = a;
			addr->a_mask |= ADDR_ATTR_PEER;
			peer_prefix = 1;
		}
	}

	nl_addr_set_prefixlen(peer_prefix ? addr->a_peer : addr->a_local,
			      addr->a_prefixlen);

	if (tb[IFA_BROADCAST]) {
		addr->a_bcast = nla_get_addr(tb[IFA_BROADCAST], addr->a_family);
		if (!addr->a_bcast)
			goto errout_free;

		addr->a_mask |= ADDR_ATTR_BROADCAST;
	}

	if (tb[IFA_ANYCAST]) {
		addr->a_anycast = nla_get_addr(tb[IFA_ANYCAST], addr->a_family);
		if (!addr->a_anycast)
			goto errout_free;

		addr->a_mask |= ADDR_ATTR_ANYCAST;
	}

	if (tb[IFA_MULTICAST]) {
		addr->a_multicast = nla_get_addr(tb[IFA_MULTICAST],
						 addr->a_family);
		if (!addr->a_multicast)
			goto errout_free;

		addr->a_mask |= ADDR_ATTR_MULTICAST;
	}

	return addr;

errout_free:
	rtnl_addr_free(addr);
errout:
	return NULL;
}
예제 #15
0
void nl_bridge::update_access_ports(rtnl_link *vxlan_link, rtnl_link *br_link,
                                    const uint16_t vid,
                                    const uint32_t tunnel_id,
                                    const std::deque<rtnl_link *> &bridge_ports,
                                    bool add) {
  // XXX pvid is currently not taken into account
  for (auto _br_port : bridge_ports) {
    auto br_port_vlans = rtnl_link_bridge_get_port_vlan(_br_port);

    if (rtnl_link_get_ifindex(vxlan_link) == rtnl_link_get_ifindex(_br_port))
      continue;

    if (br_port_vlans == nullptr)
      continue;

    if (!is_vid_set(vid, br_port_vlans->vlan_bitmap))
      continue;

    bool untagged = is_vid_set(vid, br_port_vlans->untagged_bitmap);
    int ifindex = rtnl_link_get_ifindex(_br_port);
    uint32_t pport_no = nl->get_port_id(ifindex);

    if (pport_no == 0) {
      LOG(WARNING) << __FUNCTION__ << ": ignoring unknown port "
                   << OBJ_CAST(_br_port);
      continue;
    }

    rtnl_link *link = nl->get_link(rtnl_link_get_ifindex(_br_port), AF_UNSPEC);

    VLOG(2) << __FUNCTION__ << ": vid=" << vid << ", untagged=" << untagged
            << ", tunnel_id=" << tunnel_id << ", add=" << add
            << ", ifindex=" << ifindex << ", pport_no=" << pport_no
            << ", port: " << OBJ_CAST(_br_port);

    if (add) {
      std::string port_name = std::string(rtnl_link_get_name(_br_port));

      // this is no longer a normal bridge interface thus we delete all the
      // bridging entries
      sw->l2_addr_remove_all_in_vlan(pport_no, vid);
      vxlan->create_access_port(_br_port, tunnel_id, port_name, pport_no, vid,
                                untagged, nullptr);

      auto neighs = get_fdb_entries_of_port(_br_port, vid);
      for (auto n : neighs) {
        // ignore ll addr of bridge on slave
        if (nl_addr_cmp(rtnl_link_get_addr(bridge), rtnl_neigh_get_lladdr(n)) ==
            0) {
          continue;
        }
        VLOG(3) << ": needs to be updated " << OBJ_CAST(n);
        vxlan->add_l2_neigh(n, link, br_link);
      }

    } else {
      // delete access port and all bridging entries
      vxlan->delete_access_port(_br_port, pport_no, vid, true);
      // XXX FIXME check if we have to add the VLANs again (ingress/egress)
    }
  }
}