switchdev: rename vlan vid_start to vid_begin
[deliverable/linux.git] / net / switchdev / switchdev.c
index a267f7728165f07d9842d4373fb7c16c5affe9d0..448d9199cea2718e0d4b57aa19debd93ae2ed684 100644 (file)
@@ -103,7 +103,9 @@ static void switchdev_port_attr_set_work(struct work_struct *work)
 
        rtnl_lock();
        err = switchdev_port_attr_set(asw->dev, &asw->attr);
-       BUG_ON(err);
+       if (err && err != -EOPNOTSUPP)
+               netdev_err(asw->dev, "failed (err=%d) to set attribute (id=%d)\n",
+                          err, asw->attr.id);
        rtnl_unlock();
 
        dev_put(asw->dev);
@@ -296,6 +298,36 @@ int switchdev_port_obj_del(struct net_device *dev, struct switchdev_obj *obj)
 }
 EXPORT_SYMBOL_GPL(switchdev_port_obj_del);
 
+/**
+ *     switchdev_port_obj_dump - Dump port objects
+ *
+ *     @dev: port device
+ *     @obj: object to dump
+ */
+int switchdev_port_obj_dump(struct net_device *dev, struct switchdev_obj *obj)
+{
+       const struct switchdev_ops *ops = dev->switchdev_ops;
+       struct net_device *lower_dev;
+       struct list_head *iter;
+       int err = -EOPNOTSUPP;
+
+       if (ops && ops->switchdev_port_obj_dump)
+               return ops->switchdev_port_obj_dump(dev, obj);
+
+       /* Switch device port(s) may be stacked under
+        * bond/team/vlan dev, so recurse down to dump objects on
+        * first port at bottom of stack.
+        */
+
+       netdev_for_each_lower_dev(dev, lower_dev, iter) {
+               err = switchdev_port_obj_dump(lower_dev, obj);
+               break;
+       }
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(switchdev_port_obj_dump);
+
 static DEFINE_MUTEX(switchdev_mutex);
 static RAW_NOTIFIER_HEAD(switchdev_notif_chain);
 
@@ -383,7 +415,7 @@ int switchdev_port_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
                return err;
 
        return ndo_dflt_bridge_getlink(skb, pid, seq, dev, mode,
-                                      attr.brport_flags, mask, nlflags);
+                                      attr.u.brport_flags, mask, nlflags);
 }
 EXPORT_SYMBOL_GPL(switchdev_port_bridge_getlink);
 
@@ -402,9 +434,9 @@ static int switchdev_port_br_setflag(struct net_device *dev,
                return err;
 
        if (flag)
-               attr.brport_flags |= brport_flag;
+               attr.u.brport_flags |= brport_flag;
        else
-               attr.brport_flags &= ~brport_flag;
+               attr.u.brport_flags &= ~brport_flag;
 
        return switchdev_port_attr_set(dev, &attr);
 }
@@ -466,6 +498,7 @@ static int switchdev_port_br_afspec(struct net_device *dev,
        struct switchdev_obj obj = {
                .id = SWITCHDEV_OBJ_PORT_VLAN,
        };
+       struct switchdev_obj_vlan *vlan = &obj.u.vlan;
        int rem;
        int err;
 
@@ -475,30 +508,30 @@ static int switchdev_port_br_afspec(struct net_device *dev,
                if (nla_len(attr) != sizeof(struct bridge_vlan_info))
                        return -EINVAL;
                vinfo = nla_data(attr);
-               obj.vlan.flags = vinfo->flags;
+               vlan->flags = vinfo->flags;
                if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) {
-                       if (obj.vlan.vid_start)
+                       if (vlan->vid_begin)
                                return -EINVAL;
-                       obj.vlan.vid_start = vinfo->vid;
+                       vlan->vid_begin = vinfo->vid;
                } else if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_END) {
-                       if (!obj.vlan.vid_start)
+                       if (!vlan->vid_begin)
                                return -EINVAL;
-                       obj.vlan.vid_end = vinfo->vid;
-                       if (obj.vlan.vid_end <= obj.vlan.vid_start)
+                       vlan->vid_end = vinfo->vid;
+                       if (vlan->vid_end <= vlan->vid_begin)
                                return -EINVAL;
                        err = f(dev, &obj);
                        if (err)
                                return err;
-                       memset(&obj.vlan, 0, sizeof(obj.vlan));
+                       memset(vlan, 0, sizeof(*vlan));
                } else {
-                       if (obj.vlan.vid_start)
+                       if (vlan->vid_begin)
                                return -EINVAL;
-                       obj.vlan.vid_start = vinfo->vid;
-                       obj.vlan.vid_end = vinfo->vid;
+                       vlan->vid_begin = vinfo->vid;
+                       vlan->vid_end = vinfo->vid;
                        err = f(dev, &obj);
                        if (err)
                                return err;
-                       memset(&obj.vlan, 0, sizeof(obj.vlan));
+                       memset(vlan, 0, sizeof(*vlan));
                }
        }
 
@@ -565,6 +598,145 @@ int switchdev_port_bridge_dellink(struct net_device *dev,
 }
 EXPORT_SYMBOL_GPL(switchdev_port_bridge_dellink);
 
+/**
+ *     switchdev_port_fdb_add - Add FDB (MAC/VLAN) entry to port
+ *
+ *     @ndmsg: netlink hdr
+ *     @nlattr: netlink attributes
+ *     @dev: port device
+ *     @addr: MAC address to add
+ *     @vid: VLAN to add
+ *
+ *     Add FDB entry to switch device.
+ */
+int switchdev_port_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
+                          struct net_device *dev, const unsigned char *addr,
+                          u16 vid, u16 nlm_flags)
+{
+       struct switchdev_obj obj = {
+               .id = SWITCHDEV_OBJ_PORT_FDB,
+               .u.fdb = {
+                       .addr = addr,
+                       .vid = vid,
+               },
+       };
+
+       return switchdev_port_obj_add(dev, &obj);
+}
+EXPORT_SYMBOL_GPL(switchdev_port_fdb_add);
+
+/**
+ *     switchdev_port_fdb_del - Delete FDB (MAC/VLAN) entry from port
+ *
+ *     @ndmsg: netlink hdr
+ *     @nlattr: netlink attributes
+ *     @dev: port device
+ *     @addr: MAC address to delete
+ *     @vid: VLAN to delete
+ *
+ *     Delete FDB entry from switch device.
+ */
+int switchdev_port_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],
+                          struct net_device *dev, const unsigned char *addr,
+                          u16 vid)
+{
+       struct switchdev_obj obj = {
+               .id = SWITCHDEV_OBJ_PORT_FDB,
+               .u.fdb = {
+                       .addr = addr,
+                       .vid = vid,
+               },
+       };
+
+       return switchdev_port_obj_del(dev, &obj);
+}
+EXPORT_SYMBOL_GPL(switchdev_port_fdb_del);
+
+struct switchdev_fdb_dump {
+       struct switchdev_obj obj;
+       struct sk_buff *skb;
+       struct netlink_callback *cb;
+       int idx;
+};
+
+static int switchdev_port_fdb_dump_cb(struct net_device *dev,
+                                     struct switchdev_obj *obj)
+{
+       struct switchdev_fdb_dump *dump =
+               container_of(obj, struct switchdev_fdb_dump, obj);
+       u32 portid = NETLINK_CB(dump->cb->skb).portid;
+       u32 seq = dump->cb->nlh->nlmsg_seq;
+       struct nlmsghdr *nlh;
+       struct ndmsg *ndm;
+
+       if (dump->idx < dump->cb->args[0])
+               goto skip;
+
+       nlh = nlmsg_put(dump->skb, portid, seq, RTM_NEWNEIGH,
+                       sizeof(*ndm), NLM_F_MULTI);
+       if (!nlh)
+               return -EMSGSIZE;
+
+       ndm = nlmsg_data(nlh);
+       ndm->ndm_family  = AF_BRIDGE;
+       ndm->ndm_pad1    = 0;
+       ndm->ndm_pad2    = 0;
+       ndm->ndm_flags   = NTF_SELF;
+       ndm->ndm_type    = 0;
+       ndm->ndm_ifindex = dev->ifindex;
+       ndm->ndm_state   = NUD_REACHABLE;
+
+       if (nla_put(dump->skb, NDA_LLADDR, ETH_ALEN, obj->u.fdb.addr))
+               goto nla_put_failure;
+
+       if (obj->u.fdb.vid && nla_put_u16(dump->skb, NDA_VLAN, obj->u.fdb.vid))
+               goto nla_put_failure;
+
+       nlmsg_end(dump->skb, nlh);
+
+skip:
+       dump->idx++;
+       return 0;
+
+nla_put_failure:
+       nlmsg_cancel(dump->skb, nlh);
+       return -EMSGSIZE;
+}
+
+/**
+ *     switchdev_port_fdb_dump - Dump port FDB (MAC/VLAN) entries
+ *
+ *     @skb: netlink skb
+ *     @cb: netlink callback
+ *     @dev: port device
+ *     @filter_dev: filter device
+ *     @idx:
+ *
+ *     Delete FDB entry from switch device.
+ */
+int switchdev_port_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb,
+                           struct net_device *dev,
+                           struct net_device *filter_dev, int idx)
+{
+       struct switchdev_fdb_dump dump = {
+               .obj = {
+                       .id = SWITCHDEV_OBJ_PORT_FDB,
+                       .cb = switchdev_port_fdb_dump_cb,
+               },
+               .skb = skb,
+               .cb = cb,
+               .idx = idx,
+       };
+       int err;
+
+       err = switchdev_port_obj_dump(dev, &dump.obj);
+       if (err)
+               return err;
+
+       return dump.idx;
+}
+EXPORT_SYMBOL_GPL(switchdev_port_fdb_dump);
+
 static struct net_device *switchdev_get_lowest_dev(struct net_device *dev)
 {
        const struct switchdev_ops *ops = dev->switchdev_ops;
@@ -613,10 +785,10 @@ static struct net_device *switchdev_get_dev_by_nhs(struct fib_info *fi)
                        return NULL;
 
                if (nhsel > 0) {
-                       if (prev_attr.ppid.id_len != attr.ppid.id_len)
+                       if (prev_attr.u.ppid.id_len != attr.u.ppid.id_len)
                                return NULL;
-                       if (memcmp(prev_attr.ppid.id, attr.ppid.id,
-                                  attr.ppid.id_len))
+                       if (memcmp(prev_attr.u.ppid.id, attr.u.ppid.id,
+                                  attr.u.ppid.id_len))
                                return NULL;
                }
 
@@ -627,7 +799,7 @@ static struct net_device *switchdev_get_dev_by_nhs(struct fib_info *fi)
 }
 
 /**
- *     switchdev_fib_ipv4_add - Add IPv4 route entry to switch
+ *     switchdev_fib_ipv4_add - Add/modify switch IPv4 route entry
  *
  *     @dst: route's IPv4 destination address
  *     @dst_len: destination address length (prefix length)
@@ -637,15 +809,15 @@ static struct net_device *switchdev_get_dev_by_nhs(struct fib_info *fi)
  *     @nlflags: netlink flags passed in (NLM_F_*)
  *     @tb_id: route table ID
  *
- *     Add IPv4 route entry to switch device.
+ *     Add/modify switch IPv4 route entry.
  */
 int switchdev_fib_ipv4_add(u32 dst, int dst_len, struct fib_info *fi,
                           u8 tos, u8 type, u32 nlflags, u32 tb_id)
 {
        struct switchdev_obj fib_obj = {
                .id = SWITCHDEV_OBJ_IPV4_FIB,
-               .ipv4_fib = {
-                       .dst = htonl(dst),
+               .u.ipv4_fib = {
+                       .dst = dst,
                        .dst_len = dst_len,
                        .fi = fi,
                        .tos = tos,
@@ -675,9 +847,9 @@ int switchdev_fib_ipv4_add(u32 dst, int dst_len, struct fib_info *fi,
 
        err = switchdev_port_obj_add(dev, &fib_obj);
        if (!err)
-               fi->fib_flags |= RTNH_F_EXTERNAL;
+               fi->fib_flags |= RTNH_F_OFFLOAD;
 
-       return err;
+       return err == -EOPNOTSUPP ? 0 : err;
 }
 EXPORT_SYMBOL_GPL(switchdev_fib_ipv4_add);
 
@@ -698,8 +870,8 @@ int switchdev_fib_ipv4_del(u32 dst, int dst_len, struct fib_info *fi,
 {
        struct switchdev_obj fib_obj = {
                .id = SWITCHDEV_OBJ_IPV4_FIB,
-               .ipv4_fib = {
-                       .dst = htonl(dst),
+               .u.ipv4_fib = {
+                       .dst = dst,
                        .dst_len = dst_len,
                        .fi = fi,
                        .tos = tos,
@@ -711,7 +883,7 @@ int switchdev_fib_ipv4_del(u32 dst, int dst_len, struct fib_info *fi,
        struct net_device *dev;
        int err = 0;
 
-       if (!(fi->fib_flags & RTNH_F_EXTERNAL))
+       if (!(fi->fib_flags & RTNH_F_OFFLOAD))
                return 0;
 
        dev = switchdev_get_dev_by_nhs(fi);
@@ -720,9 +892,9 @@ int switchdev_fib_ipv4_del(u32 dst, int dst_len, struct fib_info *fi,
 
        err = switchdev_port_obj_del(dev, &fib_obj);
        if (!err)
-               fi->fib_flags &= ~RTNH_F_EXTERNAL;
+               fi->fib_flags &= ~RTNH_F_OFFLOAD;
 
-       return err;
+       return err == -EOPNOTSUPP ? 0 : err;
 }
 EXPORT_SYMBOL_GPL(switchdev_fib_ipv4_del);
 
This page took 0.031967 seconds and 5 git commands to generate.