2 * ipnetconf.c "ip netconf".
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
9 * Authors: Nicolas Dichtel, <nicolas.dichtel@6wind.com>
19 #include <sys/socket.h>
20 #include <netinet/in.h>
25 #include "ip_common.h"
32 static const char * const rp_filter_names
[] = {
33 "off", "strict", "loose"
36 static void usage(void) __attribute__((noreturn
));
38 static void usage(void)
40 fprintf(stderr
, "Usage: ip netconf show [ dev STRING ]\n");
44 static void print_onoff(FILE *fp
, const char *flag
, __u32 val
)
46 if (is_json_context())
47 print_bool(PRINT_JSON
, flag
, NULL
, val
);
49 fprintf(fp
, "%s %s ", flag
, val
? "on" : "off");
52 static struct rtattr
*netconf_rta(struct netconfmsg
*ncm
)
54 return (struct rtattr
*)((char *)ncm
55 + NLMSG_ALIGN(sizeof(struct netconfmsg
)));
58 int print_netconf(struct rtnl_ctrl_data
*ctrl
, struct nlmsghdr
*n
, void *arg
)
60 FILE *fp
= (FILE *)arg
;
61 struct netconfmsg
*ncm
= NLMSG_DATA(n
);
62 int len
= n
->nlmsg_len
;
63 struct rtattr
*tb
[NETCONFA_MAX
+1];
66 if (n
->nlmsg_type
== NLMSG_ERROR
)
69 if (n
->nlmsg_type
!= RTM_NEWNETCONF
&&
70 n
->nlmsg_type
!= RTM_DELNETCONF
) {
71 fprintf(stderr
, "Not a netconf message: %08x %08x %08x\n",
72 n
->nlmsg_len
, n
->nlmsg_type
, n
->nlmsg_flags
);
76 len
-= NLMSG_SPACE(sizeof(*ncm
));
78 fprintf(stderr
, "BUG: wrong nlmsg len %d\n", len
);
82 if (filter
.family
&& filter
.family
!= ncm
->ncm_family
)
85 parse_rtattr(tb
, NETCONFA_MAX
, netconf_rta(ncm
),
86 NLMSG_PAYLOAD(n
, sizeof(*ncm
)));
88 if (tb
[NETCONFA_IFINDEX
])
89 ifindex
= rta_getattr_u32(tb
[NETCONFA_IFINDEX
]);
91 if (filter
.ifindex
&& filter
.ifindex
!= ifindex
)
94 open_json_object(NULL
);
95 if (n
->nlmsg_type
== RTM_DELNETCONF
)
96 print_bool(PRINT_ANY
, "deleted", "Deleted ", true);
98 print_string(PRINT_ANY
, "family",
99 "%s ", family_name(ncm
->ncm_family
));
101 if (tb
[NETCONFA_IFINDEX
]) {
105 case NETCONFA_IFINDEX_ALL
:
108 case NETCONFA_IFINDEX_DEFAULT
:
112 dev
= ll_index_to_name(ifindex
);
115 print_color_string(PRINT_ANY
, COLOR_IFNAME
,
116 "interface", "%s ", dev
);
119 if (tb
[NETCONFA_FORWARDING
])
120 print_onoff(fp
, "forwarding",
121 rta_getattr_u32(tb
[NETCONFA_FORWARDING
]));
123 if (tb
[NETCONFA_RP_FILTER
]) {
124 __u32 rp_filter
= rta_getattr_u32(tb
[NETCONFA_RP_FILTER
]);
126 if (rp_filter
< ARRAY_SIZE(rp_filter_names
))
127 print_string(PRINT_ANY
, "rp_filter",
129 rp_filter_names
[rp_filter
]);
131 print_uint(PRINT_ANY
, "rp_filter",
132 "rp_filter %u ", rp_filter
);
135 if (tb
[NETCONFA_MC_FORWARDING
])
136 print_onoff(fp
, "mc_forwarding",
137 rta_getattr_u32(tb
[NETCONFA_MC_FORWARDING
]));
139 if (tb
[NETCONFA_PROXY_NEIGH
])
140 print_onoff(fp
, "proxy_neigh",
141 rta_getattr_u32(tb
[NETCONFA_PROXY_NEIGH
]));
143 if (tb
[NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN
])
144 print_onoff(fp
, "ignore_routes_with_linkdown",
145 rta_getattr_u32(tb
[NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN
]));
147 if (tb
[NETCONFA_INPUT
])
148 print_onoff(fp
, "input", rta_getattr_u32(tb
[NETCONFA_INPUT
]));
151 print_string(PRINT_FP
, NULL
, "\n", NULL
);
156 static int print_netconf2(struct nlmsghdr
*n
, void *arg
)
158 return print_netconf(NULL
, n
, arg
);
161 void ipnetconf_reset_filter(int ifindex
)
163 memset(&filter
, 0, sizeof(filter
));
164 filter
.ifindex
= ifindex
;
167 static int do_show(int argc
, char **argv
)
171 struct netconfmsg ncm
;
174 .n
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct netconfmsg
)),
175 .n
.nlmsg_flags
= NLM_F_REQUEST
| NLM_F_ACK
,
176 .n
.nlmsg_type
= RTM_GETNETCONF
,
179 ipnetconf_reset_filter(0);
180 filter
.family
= preferred_family
;
183 if (strcmp(*argv
, "dev") == 0) {
185 filter
.ifindex
= ll_name_to_index(*argv
);
186 if (filter
.ifindex
<= 0) {
188 "Device \"%s\" does not exist.\n",
198 if (filter
.ifindex
&& filter
.family
!= AF_UNSPEC
) {
199 req
.ncm
.ncm_family
= filter
.family
;
200 addattr_l(&req
.n
, sizeof(req
), NETCONFA_IFINDEX
,
201 &filter
.ifindex
, sizeof(filter
.ifindex
));
203 if (rtnl_send(&rth
, &req
.n
, req
.n
.nlmsg_len
) < 0) {
204 perror("Can not send request");
207 rtnl_listen(&rth
, print_netconf
, stdout
);
209 rth
.flags
= RTNL_HANDLE_F_SUPPRESS_NLERR
;
211 if (rtnl_netconfdump_req(&rth
, filter
.family
) < 0) {
212 perror("Cannot send dump request");
217 if (rtnl_dump_filter(&rth
, print_netconf2
, stdout
) < 0) {
218 /* kernel does not support netconf dump on AF_UNSPEC;
219 * fall back to requesting by family
221 if (errno
== EOPNOTSUPP
&&
222 filter
.family
== AF_UNSPEC
) {
223 filter
.family
= AF_INET
;
226 perror("RTNETLINK answers");
227 fprintf(stderr
, "Dump terminated\n");
231 if (preferred_family
== AF_UNSPEC
&& filter
.family
== AF_INET
) {
232 preferred_family
= AF_INET6
;
233 filter
.family
= AF_INET6
;
240 int do_ipnetconf(int argc
, char **argv
)
243 if (matches(*argv
, "show") == 0 ||
244 matches(*argv
, "lst") == 0 ||
245 matches(*argv
, "list") == 0)
246 return do_show(argc
-1, argv
+1);
247 if (matches(*argv
, "help") == 0)
250 return do_show(0, NULL
);
253 "Command \"%s\" is unknown, try \"ip netconf help\".\n",