Skip to content

Commit 61c503f

Browse files
jpirkodavem330
authored andcommitted
mlxsw: spectrum_router: Implement fib4 add/del switchdev obj ops
Implement ipv4 FIB entries addition and removal. Initially, we support local and broadcast routes using "ip2me" trap action. Also, unicast routes without nexthop are supported using "local" action. Signed-off-by: Jiri Pirko <[email protected]> Reviewed-by: Ido Schimmel <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent d5a1c74 commit 61c503f

File tree

3 files changed

+259
-0
lines changed

3 files changed

+259
-0
lines changed

drivers/net/ethernet/mellanox/mlxsw/spectrum.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,5 +476,10 @@ static inline void mlxsw_sp_port_dcb_fini(struct mlxsw_sp_port *mlxsw_sp_port)
476476

477477
int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp);
478478
void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp);
479+
int mlxsw_sp_router_fib4_add(struct mlxsw_sp_port *mlxsw_sp_port,
480+
const struct switchdev_obj_ipv4_fib *fib4,
481+
struct switchdev_trans *trans);
482+
int mlxsw_sp_router_fib4_del(struct mlxsw_sp_port *mlxsw_sp_port,
483+
const struct switchdev_obj_ipv4_fib *fib4);
479484

480485
#endif

drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c

Lines changed: 245 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,19 @@ struct mlxsw_sp_fib_key {
106106
unsigned char prefix_len;
107107
};
108108

109+
enum mlxsw_sp_fib_entry_type {
110+
MLXSW_SP_FIB_ENTRY_TYPE_REMOTE,
111+
MLXSW_SP_FIB_ENTRY_TYPE_LOCAL,
112+
MLXSW_SP_FIB_ENTRY_TYPE_TRAP,
113+
};
114+
109115
struct mlxsw_sp_fib_entry {
110116
struct rhash_head ht_node;
111117
struct mlxsw_sp_fib_key key;
118+
enum mlxsw_sp_fib_entry_type type;
119+
u8 added:1;
120+
u16 rif; /* used for action local */
121+
struct mlxsw_sp_vr *vr;
112122
};
113123

114124
struct mlxsw_sp_fib {
@@ -567,3 +577,238 @@ void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp)
567577
{
568578
__mlxsw_sp_router_fini(mlxsw_sp);
569579
}
580+
581+
static int mlxsw_sp_fib_entry_op4_local(struct mlxsw_sp *mlxsw_sp,
582+
struct mlxsw_sp_fib_entry *fib_entry,
583+
enum mlxsw_reg_ralue_op op)
584+
{
585+
char ralue_pl[MLXSW_REG_RALUE_LEN];
586+
u32 *p_dip = (u32 *) fib_entry->key.addr;
587+
struct mlxsw_sp_vr *vr = fib_entry->vr;
588+
589+
mlxsw_reg_ralue_pack4(ralue_pl, vr->proto, op, vr->id,
590+
fib_entry->key.prefix_len, *p_dip);
591+
mlxsw_reg_ralue_act_local_pack(ralue_pl,
592+
MLXSW_REG_RALUE_TRAP_ACTION_NOP, 0,
593+
fib_entry->rif);
594+
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl);
595+
}
596+
597+
static int mlxsw_sp_fib_entry_op4_trap(struct mlxsw_sp *mlxsw_sp,
598+
struct mlxsw_sp_fib_entry *fib_entry,
599+
enum mlxsw_reg_ralue_op op)
600+
{
601+
char ralue_pl[MLXSW_REG_RALUE_LEN];
602+
u32 *p_dip = (u32 *) fib_entry->key.addr;
603+
struct mlxsw_sp_vr *vr = fib_entry->vr;
604+
605+
mlxsw_reg_ralue_pack4(ralue_pl, vr->proto, op, vr->id,
606+
fib_entry->key.prefix_len, *p_dip);
607+
mlxsw_reg_ralue_act_ip2me_pack(ralue_pl);
608+
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl);
609+
}
610+
611+
static int mlxsw_sp_fib_entry_op4(struct mlxsw_sp *mlxsw_sp,
612+
struct mlxsw_sp_fib_entry *fib_entry,
613+
enum mlxsw_reg_ralue_op op)
614+
{
615+
switch (fib_entry->type) {
616+
case MLXSW_SP_FIB_ENTRY_TYPE_REMOTE:
617+
return -EINVAL;
618+
case MLXSW_SP_FIB_ENTRY_TYPE_LOCAL:
619+
return mlxsw_sp_fib_entry_op4_local(mlxsw_sp, fib_entry, op);
620+
case MLXSW_SP_FIB_ENTRY_TYPE_TRAP:
621+
return mlxsw_sp_fib_entry_op4_trap(mlxsw_sp, fib_entry, op);
622+
}
623+
return -EINVAL;
624+
}
625+
626+
static int mlxsw_sp_fib_entry_op(struct mlxsw_sp *mlxsw_sp,
627+
struct mlxsw_sp_fib_entry *fib_entry,
628+
enum mlxsw_reg_ralue_op op)
629+
{
630+
switch (fib_entry->vr->proto) {
631+
case MLXSW_SP_L3_PROTO_IPV4:
632+
return mlxsw_sp_fib_entry_op4(mlxsw_sp, fib_entry, op);
633+
case MLXSW_SP_L3_PROTO_IPV6:
634+
return -EINVAL;
635+
}
636+
return -EINVAL;
637+
}
638+
639+
static int mlxsw_sp_fib_entry_update(struct mlxsw_sp *mlxsw_sp,
640+
struct mlxsw_sp_fib_entry *fib_entry)
641+
{
642+
enum mlxsw_reg_ralue_op op;
643+
644+
op = !fib_entry->added ? MLXSW_REG_RALUE_OP_WRITE_WRITE :
645+
MLXSW_REG_RALUE_OP_WRITE_UPDATE;
646+
return mlxsw_sp_fib_entry_op(mlxsw_sp, fib_entry, op);
647+
}
648+
649+
static int mlxsw_sp_fib_entry_del(struct mlxsw_sp *mlxsw_sp,
650+
struct mlxsw_sp_fib_entry *fib_entry)
651+
{
652+
return mlxsw_sp_fib_entry_op(mlxsw_sp, fib_entry,
653+
MLXSW_REG_RALUE_OP_WRITE_DELETE);
654+
}
655+
656+
struct mlxsw_sp_router_fib4_add_info {
657+
struct switchdev_trans_item tritem;
658+
struct mlxsw_sp *mlxsw_sp;
659+
struct mlxsw_sp_fib_entry *fib_entry;
660+
};
661+
662+
static void mlxsw_sp_router_fib4_add_info_destroy(void const *data)
663+
{
664+
const struct mlxsw_sp_router_fib4_add_info *info = data;
665+
struct mlxsw_sp_fib_entry *fib_entry = info->fib_entry;
666+
struct mlxsw_sp *mlxsw_sp = info->mlxsw_sp;
667+
668+
mlxsw_sp_fib_entry_destroy(fib_entry);
669+
mlxsw_sp_vr_put(mlxsw_sp, fib_entry->vr);
670+
kfree(info);
671+
}
672+
673+
static int
674+
mlxsw_sp_router_fib4_entry_init(struct mlxsw_sp *mlxsw_sp,
675+
const struct switchdev_obj_ipv4_fib *fib4,
676+
struct mlxsw_sp_fib_entry *fib_entry)
677+
{
678+
struct fib_info *fi = fib4->fi;
679+
680+
if (fib4->type == RTN_LOCAL || fib4->type == RTN_BROADCAST) {
681+
fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_TRAP;
682+
return 0;
683+
}
684+
if (fib4->type != RTN_UNICAST)
685+
return -EINVAL;
686+
687+
if (fi->fib_scope != RT_SCOPE_UNIVERSE) {
688+
struct mlxsw_sp_rif *r;
689+
690+
fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_LOCAL;
691+
r = mlxsw_sp_rif_find_by_dev(mlxsw_sp, fi->fib_dev);
692+
if (!r)
693+
return -EINVAL;
694+
fib_entry->rif = r->rif;
695+
return 0;
696+
}
697+
return -EINVAL;
698+
}
699+
700+
static int
701+
mlxsw_sp_router_fib4_add_prepare(struct mlxsw_sp_port *mlxsw_sp_port,
702+
const struct switchdev_obj_ipv4_fib *fib4,
703+
struct switchdev_trans *trans)
704+
{
705+
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
706+
struct mlxsw_sp_router_fib4_add_info *info;
707+
struct mlxsw_sp_fib_entry *fib_entry;
708+
struct mlxsw_sp_vr *vr;
709+
int err;
710+
711+
vr = mlxsw_sp_vr_get(mlxsw_sp, fib4->dst_len, fib4->tb_id,
712+
MLXSW_SP_L3_PROTO_IPV4);
713+
if (IS_ERR(vr))
714+
return PTR_ERR(vr);
715+
716+
fib_entry = mlxsw_sp_fib_entry_create(vr->fib, &fib4->dst,
717+
sizeof(fib4->dst), fib4->dst_len);
718+
if (!fib_entry) {
719+
err = -ENOMEM;
720+
goto err_fib_entry_create;
721+
}
722+
fib_entry->vr = vr;
723+
724+
err = mlxsw_sp_router_fib4_entry_init(mlxsw_sp, fib4, fib_entry);
725+
if (err)
726+
goto err_fib4_entry_init;
727+
728+
info = kmalloc(sizeof(*info), GFP_KERNEL);
729+
if (!info) {
730+
err = -ENOMEM;
731+
goto err_alloc_info;
732+
}
733+
info->mlxsw_sp = mlxsw_sp;
734+
info->fib_entry = fib_entry;
735+
switchdev_trans_item_enqueue(trans, info,
736+
mlxsw_sp_router_fib4_add_info_destroy,
737+
&info->tritem);
738+
return 0;
739+
740+
err_alloc_info:
741+
err_fib4_entry_init:
742+
mlxsw_sp_fib_entry_destroy(fib_entry);
743+
err_fib_entry_create:
744+
mlxsw_sp_vr_put(mlxsw_sp, vr);
745+
return err;
746+
}
747+
748+
static int
749+
mlxsw_sp_router_fib4_add_commit(struct mlxsw_sp_port *mlxsw_sp_port,
750+
const struct switchdev_obj_ipv4_fib *fib4,
751+
struct switchdev_trans *trans)
752+
{
753+
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
754+
struct mlxsw_sp_router_fib4_add_info *info;
755+
struct mlxsw_sp_fib_entry *fib_entry;
756+
struct mlxsw_sp_vr *vr;
757+
int err;
758+
759+
info = switchdev_trans_item_dequeue(trans);
760+
fib_entry = info->fib_entry;
761+
kfree(info);
762+
763+
vr = fib_entry->vr;
764+
err = mlxsw_sp_fib_entry_insert(fib_entry->vr->fib, fib_entry);
765+
if (err)
766+
goto err_fib_entry_insert;
767+
err = mlxsw_sp_fib_entry_update(mlxsw_sp, fib_entry);
768+
if (err)
769+
goto err_fib_entry_add;
770+
return 0;
771+
772+
err_fib_entry_add:
773+
mlxsw_sp_fib_entry_remove(vr->fib, fib_entry);
774+
err_fib_entry_insert:
775+
mlxsw_sp_fib_entry_destroy(fib_entry);
776+
mlxsw_sp_vr_put(mlxsw_sp, vr);
777+
return err;
778+
}
779+
780+
int mlxsw_sp_router_fib4_add(struct mlxsw_sp_port *mlxsw_sp_port,
781+
const struct switchdev_obj_ipv4_fib *fib4,
782+
struct switchdev_trans *trans)
783+
{
784+
if (switchdev_trans_ph_prepare(trans))
785+
return mlxsw_sp_router_fib4_add_prepare(mlxsw_sp_port,
786+
fib4, trans);
787+
return mlxsw_sp_router_fib4_add_commit(mlxsw_sp_port,
788+
fib4, trans);
789+
}
790+
791+
int mlxsw_sp_router_fib4_del(struct mlxsw_sp_port *mlxsw_sp_port,
792+
const struct switchdev_obj_ipv4_fib *fib4)
793+
{
794+
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
795+
struct mlxsw_sp_fib_entry *fib_entry;
796+
struct mlxsw_sp_vr *vr;
797+
798+
vr = mlxsw_sp_vr_find(mlxsw_sp, fib4->tb_id, MLXSW_SP_L3_PROTO_IPV4);
799+
if (!vr) {
800+
dev_warn(mlxsw_sp->bus_info->dev, "Failed to find virtual router for FIB4 entry being removed.\n");
801+
return -ENOENT;
802+
}
803+
fib_entry = mlxsw_sp_fib_entry_lookup(vr->fib, &fib4->dst,
804+
sizeof(fib4->dst), fib4->dst_len);
805+
if (!fib_entry) {
806+
dev_warn(mlxsw_sp->bus_info->dev, "Failed to find FIB4 entry being removed.\n");
807+
return PTR_ERR(vr);
808+
}
809+
mlxsw_sp_fib_entry_del(mlxsw_sp_port->mlxsw_sp, fib_entry);
810+
mlxsw_sp_fib_entry_remove(vr->fib, fib_entry);
811+
mlxsw_sp_fib_entry_destroy(fib_entry);
812+
mlxsw_sp_vr_put(mlxsw_sp, vr);
813+
return 0;
814+
}

drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -978,6 +978,11 @@ static int mlxsw_sp_port_obj_add(struct net_device *dev,
978978
SWITCHDEV_OBJ_PORT_VLAN(obj),
979979
trans);
980980
break;
981+
case SWITCHDEV_OBJ_ID_IPV4_FIB:
982+
err = mlxsw_sp_router_fib4_add(mlxsw_sp_port,
983+
SWITCHDEV_OBJ_IPV4_FIB(obj),
984+
trans);
985+
break;
981986
case SWITCHDEV_OBJ_ID_PORT_FDB:
982987
err = mlxsw_sp_port_fdb_static_add(mlxsw_sp_port,
983988
SWITCHDEV_OBJ_PORT_FDB(obj),
@@ -1123,6 +1128,10 @@ static int mlxsw_sp_port_obj_del(struct net_device *dev,
11231128
err = mlxsw_sp_port_vlans_del(mlxsw_sp_port,
11241129
SWITCHDEV_OBJ_PORT_VLAN(obj));
11251130
break;
1131+
case SWITCHDEV_OBJ_ID_IPV4_FIB:
1132+
err = mlxsw_sp_router_fib4_del(mlxsw_sp_port,
1133+
SWITCHDEV_OBJ_IPV4_FIB(obj));
1134+
break;
11261135
case SWITCHDEV_OBJ_ID_PORT_FDB:
11271136
err = mlxsw_sp_port_fdb_static_del(mlxsw_sp_port,
11281137
SWITCHDEV_OBJ_PORT_FDB(obj));

0 commit comments

Comments
 (0)